/* do not edit automatically generated by mc from pge.  */
/* pge.mod master source file of the ebnf parser generator.

Copyright (C) 2003-2023 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Modula-2; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (TRUE)
#      define TRUE (1==1)
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#include <stddef.h>
#include <string.h>
#include <limits.h>
#   include "GStorage.h"
#   include "Gmcrts.h"
#if defined(__cplusplus)
#   undef NULL
#   define NULL 0
#endif
#   include "GPushBackInput.h"
#   include "Gbnflex.h"
#   include "GStrLib.h"
#   include "GStorage.h"
#   include "GNameKey.h"
#   include "GNumberIO.h"
#   include "GSymbolKey.h"
#   include "GLists.h"
#   include "GDynamicStrings.h"
#   include "GASCII.h"
#   include "GStrIO.h"
#   include "GStdIO.h"
#   include "GDebug.h"
#   include "GArgs.h"
#   include "GSYSTEM.h"
#   include "Glibc.h"
#   include "GOutput.h"
#   include "GM2RTS.h"

#   define MaxCodeHunkLength 8192
#   define MaxFileName 8192
#   define MaxString 8192
#   define DefaultRecovery TRUE
#   define MaxElementsInSet 32
#   define BaseRightLimit 75
#   define BaseRightMargin 50
#   define BaseNewLine 3
typedef struct pge_termdesc_r pge_termdesc;

typedef pge_termdesc *pge_TermDesc;

typedef struct pge_DoProcedure_p pge_DoProcedure;

typedef unsigned int pge_SetOfStop;

typedef struct pge__T1_r pge__T1;

typedef pge__T1 *pge_IdentDesc;

typedef struct pge__T2_r pge__T2;

typedef pge__T2 *pge_ProductionDesc;

typedef struct pge__T3_r pge__T3;

typedef pge__T3 *pge_StatementDesc;

typedef struct pge__T4_r pge__T4;

typedef pge__T4 *pge_ExpressionDesc;

typedef struct pge__T5_r pge__T5;

typedef struct pge__T6_r pge__T6;

typedef pge__T6 *pge_FollowDesc;

typedef struct pge__T7_r pge__T7;

typedef pge__T7 *pge_SetDesc;

typedef struct pge__T8_r pge__T8;

typedef pge__T8 *pge_CodeDesc;

typedef struct pge__T9_r pge__T9;

typedef pge__T9 *pge_CodeHunk;

typedef struct pge__T10_a pge__T10;

typedef struct pge__T11_a pge__T11;

typedef enum {pge_idel, pge_tokel, pge_litel} pge_ElementType;

typedef enum {pge_m2none, pge_m2if, pge_m2elsif, pge_m2while} pge_m2condition;

typedef enum {pge_unknown, pge_true, pge_false} pge_TraverseResult;

typedef enum {pge_id, pge_lit, pge_sub, pge_opt, pge_mult, pge_m2} pge_FactorType;

typedef pge__T5 *pge_FactorDesc;

struct pge_termdesc_r {
                        pge_FactorDesc factor;
                        pge_TermDesc next;
                        pge_FollowDesc followinfo;
                        unsigned int line;
                      };

typedef void (*pge_DoProcedure_t) (pge_ProductionDesc);
struct pge_DoProcedure_p { pge_DoProcedure_t proc; };

struct pge__T1_r {
                   pge_ProductionDesc definition;
                   NameKey_Name name;
                   unsigned int line;
                 };

struct pge__T2_r {
                   pge_ProductionDesc next;
                   pge_StatementDesc statement;
                   pge_SetDesc first;
                   unsigned int firstsolved;
                   pge_FollowDesc followinfo;
                   unsigned int line;
                   NameKey_Name description;
                 };

struct pge__T3_r {
                   pge_IdentDesc ident;
                   pge_ExpressionDesc expr;
                   pge_FollowDesc followinfo;
                   unsigned int line;
                 };

struct pge__T4_r {
                   pge_TermDesc term;
                   pge_FollowDesc followinfo;
                   unsigned int line;
                 };

struct pge__T5_r {
                   pge_FollowDesc followinfo;
                   pge_FactorDesc next;
                   unsigned int line;
                   pge_FactorDesc pushed;
                   pge_FactorType type;  /* case tag */
                   union {
                           pge_IdentDesc ident;
                           NameKey_Name string;
                           pge_ExpressionDesc expr;
                           pge_CodeDesc code;
                         };
                 };

struct pge__T6_r {
                   unsigned int calcfollow;
                   pge_SetDesc follow;
                   pge_TraverseResult reachend;
                   pge_TraverseResult epsilon;
                   unsigned int line;
                 };

struct pge__T7_r {
                   pge_SetDesc next;
                   pge_ElementType type;  /* case tag */
                   union {
                           pge_IdentDesc ident;
                           NameKey_Name string;
                         };
                 };

struct pge__T8_r {
                   pge_CodeHunk code;
                   unsigned int indent;
                   unsigned int line;
                 };

struct pge__T10_a { char array[MaxCodeHunkLength+1]; };
struct pge__T11_a { char array[MaxFileName+1]; };
struct pge__T9_r {
                   pge__T10 codetext;
                   pge_CodeHunk next;
                 };

static unsigned int LastLineNo;
static unsigned int Finished;
static unsigned int SuppressFileLineTag;
static unsigned int KeywordFormatting;
static unsigned int PrettyPrint;
static unsigned int EmitCode;
static unsigned int Texinfo;
static unsigned int Sphinx;
static unsigned int FreeDocLicense;
static unsigned int Debugging;
static unsigned int WasNoError;
static unsigned int LinePrologue;
static unsigned int LineEpilogue;
static unsigned int LineDeclaration;
static pge_CodeHunk CodePrologue;
static pge_CodeHunk CodeEpilogue;
static pge_CodeHunk CodeDeclaration;
static pge_ProductionDesc CurrentProduction;
static pge_ProductionDesc TailProduction;
static pge_ProductionDesc HeadProduction;
static pge_ExpressionDesc CurrentExpression;
static pge_TermDesc CurrentTerm;
static pge_FactorDesc CurrentFactor;
static pge_IdentDesc CurrentIdent;
static pge_StatementDesc CurrentStatement;
static pge_SetDesc CurrentSetDesc;
static SymbolKey_SymbolTree ReverseValues;
static SymbolKey_SymbolTree Values;
static SymbolKey_SymbolTree ReverseAliases;
static SymbolKey_SymbolTree Aliases;
static NameKey_Name ModuleName;
static NameKey_Name LastLiteral;
static NameKey_Name LastIdent;
static NameKey_Name SymIsProc;
static NameKey_Name TokenTypeProc;
static NameKey_Name ErrorProcArray;
static NameKey_Name ErrorProcString;
static pge__T11 ArgName;
static pge__T11 FileName;
static unsigned int OnLineStart;
static unsigned int BeginningOfLine;
static unsigned int Indent;
static unsigned int EmittedVar;
static unsigned int ErrorRecovery;
static unsigned int LargestValue;
static unsigned int InitialElement;
static unsigned int ParametersUsed;

/*
   DescribeStop - issues a message explaining what tokens were expected
*/

static DynamicStrings_String DescribeStop (pge_SetOfStop stopset);

/*
   DescribeError - issues a message explaining what tokens were expected
*/

static void DescribeError (void);

/*
   AddEntry - adds an entry into, t, containing [def:value].
*/

static void AddEntry (SymbolKey_SymbolTree *t, NameKey_Name def, NameKey_Name value);

/*
   Format1 - converts string, src, into, dest, together with encapsulated
             entity, n. It only formats the first %s or %d with n.
*/

static void Format1 (const char *src_, unsigned int _src_high, unsigned int n, char *dest, unsigned int _dest_high);

/*
   WarnError1 -
*/

static void WarnError1 (const char *a_, unsigned int _a_high, unsigned int n);

/*
   PrettyFollow -
*/

static void PrettyFollow (const char *start_, unsigned int _start_high, const char *end_, unsigned int _end_high, pge_FollowDesc f);

/*
   NewFollow - creates a new follow descriptor and returns the data structure.
*/

static pge_FollowDesc NewFollow (void);

/*
   AssignEpsilon - assigns the epsilon value and sets the epsilon to value,
                   providing condition is TRUE.
*/

static void AssignEpsilon (unsigned int condition, pge_FollowDesc f, pge_TraverseResult value);

/*
   GetEpsilon - returns the value of epsilon
*/

static pge_TraverseResult GetEpsilon (pge_FollowDesc f);

/*
   AssignReachEnd - assigns the reachend value providing that, condition, is TRUE.
*/

static void AssignReachEnd (unsigned int condition, pge_FollowDesc f, pge_TraverseResult value);

/*
   GetReachEnd - returns the value of reachend
*/

static pge_TraverseResult GetReachEnd (pge_FollowDesc f);

/*
   AssignFollow - assigns the follow set and sets the calcfollow to TRUE.
*/

static void AssignFollow (pge_FollowDesc f, pge_SetDesc s);

/*
   GetFollow - returns the follow set.
*/

static pge_SetDesc GetFollow (pge_FollowDesc f);

/*
   NewProduction - creates a new production and returns the data structure.
*/

static pge_ProductionDesc NewProduction (void);

/*
   NewFactor -
*/

static pge_FactorDesc NewFactor (void);

/*
   NewTerm - returns a new term.
*/

static pge_TermDesc NewTerm (void);

/*
   NewExpression - returns a new expression.
*/

static pge_ExpressionDesc NewExpression (void);

/*
   NewStatement - returns a new statement.
*/

static pge_StatementDesc NewStatement (void);

/*
   NewSetDesc - creates a new set description and returns the data structure.
*/

static pge_SetDesc NewSetDesc (void);

/*
   NewCodeDesc - creates a new code descriptor and initializes all fields to zero.
*/

static pge_CodeDesc NewCodeDesc (void);

/*
   CodeFragmentPrologue - consumes code text up to a "%" after a newline.
*/

static void CodeFragmentPrologue (void);

/*
   CodeFragmentEpilogue - consumes code text up to a "%" after a newline.
*/

static void CodeFragmentEpilogue (void);

/*
   CodeFragmentDeclaration - consumes code text up to a "%" after a newline.
*/

static void CodeFragmentDeclaration (void);

/*
   GetCodeFragment - collects the code fragment up until ^ %
*/

static void GetCodeFragment (pge_CodeHunk *h);

/*
   WriteCodeHunkList - writes the CodeHunk list in the correct order.
*/

static void WriteCodeHunkList (pge_CodeHunk l);

/*
   WriteIndent - writes, n, spaces.
*/

static void WriteIndent (unsigned int n);

/*
   CheckWrite -
*/

static void CheckWrite (char ch, unsigned int *curpos, unsigned int left, unsigned int *seentext);

/*
   WriteStringIndent - writes a string but it will try and remove upto indent spaces
                       if they exist.
*/

static void WriteStringIndent (const char *a_, unsigned int _a_high, unsigned int indent, unsigned int *curpos, unsigned int left, unsigned int *seentext);

/*
   WriteCodeHunkListIndent - writes the CodeHunk list in the correct order
                             but it removes up to indent spaces if they exist.
*/

static void WriteCodeHunkListIndent (pge_CodeHunk l, unsigned int indent, unsigned int *curpos, unsigned int left, unsigned int *seentext);

/*
   Add - adds a character to a code hunk and creates another code hunk if necessary.
*/

static pge_CodeHunk Add (pge_CodeHunk *p, char ch, unsigned int *i);

/*
   ConsHunk - combine two possible code hunks.
*/

static void ConsHunk (pge_CodeHunk *p, pge_CodeHunk q);

/*
   GetName - returns the next symbol which is checked for a legal name.
*/

static NameKey_Name GetName (void);

/*
   SyntaxError - after a syntax error we skip all tokens up until we reach
                 a stop symbol.
*/

static void SyntaxError (pge_SetOfStop stop);

/*
   SyntaxCheck -
*/

static void SyntaxCheck (pge_SetOfStop stop);

/*
   Expect -
*/

static void Expect (bnflex_TokenType t, pge_SetOfStop stop);

/*
   Ident - error checking varient of Ident
*/

static void Ident (pge_SetOfStop stop);

/*
   Modula2Code - error checking varient of Modula2Code
*/

static void Modula2Code (pge_SetOfStop stop);

/*
   StartModName    := % ModuleName := GetName() ;  ignore begintok  CodeFragmentPrologue % =:
*/

static void StartModName (pge_SetOfStop stop);

/*
   EndModName    :=
*/

static void EndModName (pge_SetOfStop stop);

/*
   DoDeclaration := % CodeFragmentDeclaration % =:
*/

static void DoDeclaration (pge_SetOfStop stop);

/*
   CollectLiteral := 
                     % LastLiteral := GetCurrentToken() ;
                       AdvanceToken ;  %
                     

   first  symbols:literaltok
   
   cannot reachend
*/

static void CollectLiteral (pge_SetOfStop stopset);

/*
   CollectTok := 
                 % CurrentSetDesc := NewSetDesc() ;
                   WITH CurrentSetDesc^ DO
                      type   := tokel ;
                      string := GetCurrentToken() ;
                   END ;
                   IF NOT ContainsSymKey(Values, GetCurrentToken())
                   THEN
                      AddEntry(Values, GetCurrentToken(), LargestValue) ;
                      AddEntry(ReverseValues, Name(LargestValue), GetCurrentToken()) ;
                      AddEntry(Aliases, GetCurrentToken(), GetCurrentToken()) ;
                      AddEntry(ReverseAliases, GetCurrentToken(), GetCurrentToken()) ;
                      INC(LargestValue)
                   END ;
                   AdvanceToken() ;  %
                 

   first  symbols:identtok
   
   cannot reachend
*/

static void CollectTok (pge_SetOfStop stopset);

/*
   DefineToken := 
                  % AddEntry(Aliases, LastLiteral, GetCurrentToken()) ;
                    AddEntry(ReverseAliases, GetCurrentToken(), LastLiteral) ;
                    AddEntry(Values, GetCurrentToken(), LargestValue) ;
                    AddEntry(ReverseValues, Name(LargestValue), GetCurrentToken()) ;
                    INC(LargestValue) ;
                    AdvanceToken ;  %
                  

   first  symbols:identtok
   
   cannot reachend
*/

static void DefineToken (pge_SetOfStop stopset);

/*
   Rules := '%' 'rules' { Defs  } ExtBNF 

   first  symbols:codetok
   
   cannot reachend
*/

static void Rules (pge_SetOfStop stopset);

/*
   Special := Ident 
              % VAR p: ProductionDesc ;  %
              
              % p                           := NewProduction() ;
                p^.statement                := NewStatement() ;
                p^.statement^.followinfo^.calcfollow := TRUE ;
                p^.statement^.followinfo^.epsilon    := false ;
                p^.statement^.followinfo^.reachend   := false ;
                p^.statement^.ident         := CurrentIdent ;
                p^.statement^.expr          := NIL ;
                p^.firstsolved              := TRUE ;
                p^.followinfo^.calcfollow   := TRUE ;
                p^.followinfo^.epsilon      := false ;
                p^.followinfo^.reachend     := false  %
              First Follow [ 'epsilon' 
                             % p^.statement^.followinfo^.epsilon  := true ;   these are not used - but they are displayed when debugging 
                               p^.statement^.followinfo^.reachend := true ;
                               p^.followinfo^.epsilon  := true ;
                               p^.followinfo^.reachend := true
                                %
                              ] [ Literal 
                                  % p^.description := LastLiteral  %
                                   ] 

   first  symbols:identtok
   
   cannot reachend
*/

static void Special (pge_SetOfStop stopset);

/*
   Factor := '%' Modula2Code '%'  | 
             Ident 
             % WITH CurrentFactor^ DO
                  type  := id ;
                  ident := CurrentIdent
               END ;  %
              | Literal 
             % WITH CurrentFactor^ DO
                  type   := lit ;
                  string := LastLiteral ;
                  IF GetSymKey(Aliases, LastLiteral)=NulName
                  THEN
                     WarnError1('no token defined for literal %s', LastLiteral)
                  END
               END ;  %
              | '{' 
             % WITH CurrentFactor^ DO
                  type := mult ;
                  expr := NewExpression() ;
                  CurrentExpression := expr ;
               END ;  %
             Expression '}'  | '[' 
             % WITH CurrentFactor^ DO
                  type := opt ;
                  expr := NewExpression() ;
                  CurrentExpression := expr ;
               END ;  %
             Expression ']'  | '(' 
             % WITH CurrentFactor^ DO
                  type := sub ;
                  expr := NewExpression() ;
                  CurrentExpression := expr ;
               END ;  %
             Expression ')' 

   first  symbols:dquotetok, squotetok, lparatok, lsparatok, lcparatok, identtok, codetok
   
   cannot reachend
*/

static void Factor (pge_SetOfStop stopset);

/*
   Statement := 
                % VAR i: IdentDesc ;  %
                Ident 
                % VAR p: ProductionDesc ;  %
                
                % p := FindDefinition(CurrentIdent^.name) ;
                  IF p=NIL
                  THEN
                     p := NewProduction()
                  ELSE
                     IF NOT ((p^.statement=NIL) OR (p^.statement^.expr=NIL))
                     THEN
                        WarnError1('already declared rule %s', CurrentIdent^.name)
                     END
                  END ;
                  i := CurrentIdent ;  %
                ':=' 
                % VAR e: ExpressionDesc ;  %
                
                % e := NewExpression() ;
                  CurrentExpression := e ;  %
                
                % VAR s: StatementDesc ;  %
                
                % s := NewStatement() ;
                  WITH s^ DO
                     ident := i ;
                     expr  := e
                  END ;  %
                Expression 
                % p^.statement := s ;  %
                '=:' 

   first  symbols:identtok
   
   cannot reachend
*/

static void Statement (pge_SetOfStop stopset);

/*
   Defs := 'special' Special  | 'token' Token  | 
           'error' ErrorProcedures  | 
           'tokenfunc' TokenProcedure  | 
           'symfunc' SymProcedure 

   first  symbols:symfunctok, tfunctok, errortok, tokentok, specialtok
   
   cannot reachend
*/

static void Defs (pge_SetOfStop stopset);

/*
   ExtBNF := 'BNF' { Production  } 'FNB' 

   first  symbols:BNFtok
   
   cannot reachend
*/

static void ExtBNF (pge_SetOfStop stopset);

/*
   Main := Header Decls Footer Rules 

   first  symbols:codetok
   
   cannot reachend
*/

static void Main (pge_SetOfStop stopset);

/*
   Header := '%' 'module' StartModName 

   first  symbols:codetok
   
   cannot reachend
*/

static void Header (pge_SetOfStop stopset);

/*
   Decls := '%' 'declaration' DoDeclaration 

   first  symbols:codetok
   
   cannot reachend
*/

static void Decls (pge_SetOfStop stopset);

/*
   Footer := '%' 'module' EndModName 

   first  symbols:codetok
   
   cannot reachend
*/

static void Footer (pge_SetOfStop stopset);

/*
   First := 'first' '{' { LitOrTokenOrIdent 
                          % WITH CurrentSetDesc^ DO
                               next := TailProduction^.first ;
                            END ;
                            TailProduction^.first := CurrentSetDesc
                             %
                           } '}' 

   first  symbols:firsttok
   
   cannot reachend
*/

static void First (pge_SetOfStop stopset);

/*
   Follow := 'follow' '{' { LitOrTokenOrIdent 
                            % WITH CurrentSetDesc^ DO
                                 next := TailProduction^.followinfo^.follow ;
                              END ;
                              TailProduction^.followinfo^.follow := CurrentSetDesc
                               %
                             } '}' 

   first  symbols:followtok
   
   cannot reachend
*/

static void Follow (pge_SetOfStop stopset);

/*
   LitOrTokenOrIdent := Literal 
                        % CurrentSetDesc := NewSetDesc() ;
                          WITH CurrentSetDesc^ DO
                             type   := litel ;
                             string := LastLiteral ;
                          END ;
                           %
                         | '<' CollectTok '>'  | 
                        Ident 
                        % CurrentSetDesc := NewSetDesc() ;
                          WITH CurrentSetDesc^ DO
                             type   := idel ;
                             ident  := CurrentIdent ;
                          END ;
                           %
                        

   first  symbols:dquotetok, squotetok, identtok, lesstok
   
   cannot reachend
*/

static void LitOrTokenOrIdent (pge_SetOfStop stopset);

/*
   Literal := '"' CollectLiteral '"'  | 
              "'" CollectLiteral "'" 

   first  symbols:squotetok, dquotetok
   
   cannot reachend
*/

static void Literal (pge_SetOfStop stopset);

/*
   Token := Literal DefineToken 

   first  symbols:dquotetok, squotetok
   
   cannot reachend
*/

static void Token (pge_SetOfStop stopset);

/*
   ErrorProcedures := Literal 
                      % ErrorProcArray := LastLiteral  %
                      Literal 
                      % ErrorProcString := LastLiteral  %
                      

   first  symbols:dquotetok, squotetok
   
   cannot reachend
*/

static void ErrorProcedures (pge_SetOfStop stopset);

/*
   TokenProcedure := Literal 
                     % TokenTypeProc := LastLiteral  %
                     

   first  symbols:dquotetok, squotetok
   
   cannot reachend
*/

static void TokenProcedure (pge_SetOfStop stopset);

/*
   SymProcedure := Literal 
                   % SymIsProc := LastLiteral  %
                   

   first  symbols:dquotetok, squotetok
   
   cannot reachend
*/

static void SymProcedure (pge_SetOfStop stopset);

/*
   Production := Statement 

   first  symbols:identtok
   
   cannot reachend
*/

static void Production (pge_SetOfStop stopset);

/*
   Expression := 
                 % VAR t1, t2: TermDesc ;
                       e     : ExpressionDesc ;  %
                 
                 % e := CurrentExpression ;
                   t1 := NewTerm() ;
                   CurrentTerm := t1 ;  %
                 Term 
                 % e^.term := t1 ;  %
                 { '|' 
                   % t2 := NewTerm() ;
                     CurrentTerm := t2  %
                   Term 
                   % t1^.next := t2 ;
                     t1 := t2  %
                    } 

   first  symbols:dquotetok, squotetok, lparatok, lsparatok, lcparatok, identtok, codetok
   
   cannot reachend
*/

static void Expression (pge_SetOfStop stopset);

/*
   Term := 
           % VAR    t1: TermDesc ; f1, f2: FactorDesc ;  %
           
           % CurrentFactor := NewFactor() ;
             f1 := CurrentFactor ;
             t1 := CurrentTerm ;  %
           Factor 
           % t1^.factor := f1 ;
             f2 := NewFactor() ;
             CurrentFactor := f2  %
           { Factor 
             % f1^.next := f2 ;
               f1 := f2 ;
               f2 := NewFactor() ;
               CurrentFactor := f2 ;  %
              } 

   first  symbols:squotetok, dquotetok, codetok, identtok, lcparatok, lsparatok, lparatok
   
   cannot reachend
*/

static void Term (pge_SetOfStop stopset);

/*
   GetDefinitionName - returns the name of the rule inside, p.
*/

static NameKey_Name GetDefinitionName (pge_ProductionDesc p);

/*
   FindDefinition - searches and returns the rule which defines, n.
*/

static pge_ProductionDesc FindDefinition (NameKey_Name n);

/*
   BackPatchIdent - found an ident, i, we must look for the corresponding rule and
                    set the definition accordingly.
*/

static void BackPatchIdent (pge_IdentDesc i);

/*
   BackPatchFactor - runs through the factor looking for an ident
*/

static void BackPatchFactor (pge_FactorDesc f);

/*
   BackPatchTerm - runs through all terms to find idents.
*/

static void BackPatchTerm (pge_TermDesc t);

/*
   BackPatchExpression - runs through the term to find any idents.
*/

static void BackPatchExpression (pge_ExpressionDesc e);

/*
   BackPatchSet -
*/

static void BackPatchSet (pge_SetDesc s);

/*
   BackPatchIdentToDefinitions - search through all the rules and add a link from any ident
                                 to the definition.
*/

static void BackPatchIdentToDefinitions (pge_ProductionDesc d);

/*
   CalculateFirstAndFollow -
*/

static void CalculateFirstAndFollow (pge_ProductionDesc p);

/*
   ForeachRuleDo -
*/

static void ForeachRuleDo (pge_DoProcedure p);

/*
   WhileNotCompleteDo -
*/

static void WhileNotCompleteDo (pge_DoProcedure p);

/*
   NewLine - generate a newline and indent.
*/

static void NewLine (unsigned int Left);

/*
   CheckNewLine -
*/

static void CheckNewLine (unsigned int Left);

/*
   IndentString - writes out a string with a preceeding indent.
*/

static void IndentString (const char *a_, unsigned int _a_high);

/*
   KeyWord - writes out a keywork with optional formatting directives.
*/

static void KeyWord (NameKey_Name n);

/*
   PrettyPara -
*/

static void PrettyPara (const char *c1_, unsigned int _c1_high, const char *c2_, unsigned int _c2_high, pge_ExpressionDesc e, unsigned int Left);

/*
   WriteKeyTexinfo -
*/

static void WriteKeyTexinfo (NameKey_Name s);

/*
   PrettyCommentFactor -
*/

static void PrettyCommentFactor (pge_FactorDesc f, unsigned int Left);

/*
   PeepTerm - returns the length of characters in term.
*/

static unsigned int PeepTerm (pge_TermDesc t);

/*
   PeepExpression - returns the length of the expression.
*/

static unsigned int PeepExpression (pge_ExpressionDesc e);

/*
   PeepFactor - returns the length of character in the factor
*/

static unsigned int PeepFactor (pge_FactorDesc f);

/*
   PrettyCommentTerm -
*/

static void PrettyCommentTerm (pge_TermDesc t, unsigned int Left);

/*
   PrettyCommentExpression -
*/

static void PrettyCommentExpression (pge_ExpressionDesc e, unsigned int Left);

/*
   PrettyCommentStatement -
*/

static void PrettyCommentStatement (pge_StatementDesc s, unsigned int Left);

/*
   PrettyCommentProduction - generates the comment for rule, p.
*/

static void PrettyCommentProduction (pge_ProductionDesc p);

/*
   PrettyPrintProduction - pretty prints the ebnf rule, p.
*/

static void PrettyPrintProduction (pge_ProductionDesc p);

/*
   EmitFileLineTag - emits a line and file tag using the C preprocessor syntax.
*/

static void EmitFileLineTag (unsigned int line);

/*
   EmitRule - generates a comment and code for rule, p.
*/

static void EmitRule (pge_ProductionDesc p);

/*
   CodeCondition -
*/

static void CodeCondition (pge_m2condition m);

/*
   CodeThenDo - codes a "THEN" or "DO" depending upon, m.
*/

static void CodeThenDo (pge_m2condition m);

/*
   CodeElseEnd - builds an ELSE END statement using string, end.
*/

static void CodeElseEnd (const char *end_, unsigned int _end_high, unsigned int consumed, pge_FactorDesc f, unsigned int inopt);

/*
   CodeEnd - codes a "END" depending upon, m.
*/

static void CodeEnd (pge_m2condition m, pge_TermDesc t, unsigned int consumed, pge_FactorDesc f, unsigned int inopt);

/*
   EmitNonVarCode - writes out, code, providing it is not a variable declaration.
*/

static void EmitNonVarCode (pge_CodeDesc code, unsigned int curpos, unsigned int left);

/*
   ChainOn -
*/

static pge_FactorDesc ChainOn (pge_FactorDesc codeStack, pge_FactorDesc f);

/*
   FlushCode -
*/

static void FlushCode (pge_FactorDesc *codeStack);

/*
   CodeFactor -
*/

static void CodeFactor (pge_FactorDesc f, pge_TermDesc t, pge_m2condition l, pge_m2condition n, unsigned int inopt, unsigned int inwhile, unsigned int consumed, pge_FactorDesc codeStack);

/*
   CodeTerm -
*/

static void CodeTerm (pge_TermDesc t, pge_m2condition m, unsigned int inopt, unsigned int inwhile, unsigned int consumed, pge_FactorDesc codeStack);

/*
   CodeExpression -
*/

static void CodeExpression (pge_ExpressionDesc e, pge_m2condition m, unsigned int inopt, unsigned int inwhile, unsigned int consumed, pge_FactorDesc codeStack);

/*
   CodeStatement -
*/

static void CodeStatement (pge_StatementDesc s, pge_m2condition m);

/*
   CodeProduction - only encode grammer rules which are not special.
*/

static void CodeProduction (pge_ProductionDesc p);

/*
   RecoverCondition -
*/

static void RecoverCondition (pge_m2condition m);

/*
   ConditionIndent - returns the number of spaces indentation created via, m.
*/

static unsigned int ConditionIndent (pge_m2condition m);

/*
   WriteGetTokenType - writes out the method of determining the token type.
*/

static void WriteGetTokenType (void);

/*
   NumberOfElements - returns the number of elements in set, to, which lie between low..high
*/

static unsigned int NumberOfElements (pge_SetDesc to, unsigned int low, unsigned int high);

/*
   WriteElement - writes the literal name for element, e.
*/

static void WriteElement (unsigned int e);

/*
   EmitIsInSet - writes out the equivalent of GetTokenType() IN { toset }
*/

static void EmitIsInSet (pge_SetDesc to, NameKey_Name low, NameKey_Name high);

/*
   EmitIsInSubSet - writes out a test to see whether GetTokenype() is in { subset }
*/

static void EmitIsInSubSet (pge_SetDesc to, unsigned int low, unsigned int high);

/*
   EmitIsInFirst -
*/

static void EmitIsInFirst (pge_SetDesc to, pge_m2condition m);
static void FlushRecoverCode (pge_FactorDesc *codeStack);

/*
   RecoverFactor -
*/

static void RecoverFactor (pge_FactorDesc f, pge_m2condition m, pge_FactorDesc codeStack);

/*
   OptExpSeen - returns TRUE if we can see an optional expression in the factor.
                This is not the same as epsilon. Example { '+' } matches epsilon as
                well as { '+' | '-' } but OptExpSeen returns TRUE in the second case
                and FALSE in the first.
*/

static unsigned int OptExpSeen (pge_FactorDesc f);

/*
   RecoverTerm -
*/

static void RecoverTerm (pge_TermDesc t, pge_m2condition new_, pge_m2condition old);

/*
   RecoverExpression -
*/

static void RecoverExpression (pge_ExpressionDesc e, pge_m2condition new_, pge_m2condition old);

/*
   RecoverStatement -
*/

static void RecoverStatement (pge_StatementDesc s, pge_m2condition m);

/*
   EmitFirstFactor - generate a list of all first tokens between the range: low..high.
*/

static void EmitFirstFactor (pge_FactorDesc f, unsigned int low, unsigned int high);

/*
   EmitUsed -
*/

static void EmitUsed (unsigned int wordno);

/*
   EmitStopParameters - generate the stop set.
*/

static void EmitStopParameters (unsigned int FormalParameters);

/*
   IsBetween - returns TRUE if the value of the token, string, is
               in the range: low..high
*/

static unsigned int IsBetween (NameKey_Name string, unsigned int low, unsigned int high);

/*
   IsEmptySet - returns TRUE if no elements exist in set, to, with values, low..high.
*/

static unsigned int IsEmptySet (pge_SetDesc to, unsigned int low, unsigned int high);

/*
   EmitSet - emits the tokens in the set, to, which have values low..high
*/

static void EmitSet (pge_SetDesc to, unsigned int low, unsigned int high);

/*
   EmitSetName - emits the tokens in the set, to, which have values low..high, using
                 their names.
*/

static void EmitSetName (pge_SetDesc to, unsigned int low, unsigned int high);

/*
   EmitStopParametersAndSet - generates the stop parameters together with a set
                              inclusion of all the symbols in set, to.
*/

static void EmitStopParametersAndSet (pge_SetDesc to);

/*
   EmitSetAsParameters - generates the first symbols as parameters to a set function.
*/

static void EmitSetAsParameters (pge_SetDesc to);

/*
   EmitStopParametersAndFollow - generates the stop parameters together with a set
                                 inclusion of all the follow symbols for subsequent
                                 sentances.
*/

static void EmitStopParametersAndFollow (pge_FactorDesc f, pge_m2condition m);

/*
   EmitFirstAsParameters -
*/

static void EmitFirstAsParameters (pge_FactorDesc f);

/*
   RecoverProduction - only encode grammer rules which are not special.
                       Generate error recovery code.
*/

static void RecoverProduction (pge_ProductionDesc p);

/*
   IsWhite - returns TRUE if, ch, is a space or a tab.
*/

static unsigned int IsWhite (char ch);

/*
   FindStr - returns TRUE if, str, was seen inside the code hunk
*/

static unsigned int FindStr (pge_CodeHunk *code, unsigned int *i, const char *str_, unsigned int _str_high);

/*
   WriteUpto -
*/

static void WriteUpto (pge_CodeHunk code, pge_CodeHunk upto, unsigned int limit);

/*
   CheckForVar - checks for any local variables which need to be emitted during
                 this production.
*/

static void CheckForVar (pge_CodeHunk code);

/*
   VarFactor -
*/

static void VarFactor (pge_FactorDesc f);

/*
   VarTerm -
*/

static void VarTerm (pge_TermDesc t);

/*
   VarExpression -
*/

static void VarExpression (pge_ExpressionDesc e);

/*
   VarStatement -
*/

static void VarStatement (pge_StatementDesc s);

/*
   VarProduction - writes out all variable declarations.
*/

static void VarProduction (pge_ProductionDesc p);

/*
   In - returns TRUE if token, s, is already in the set, to.
*/

static unsigned int In (pge_SetDesc to, NameKey_Name s);

/*
   IntersectionIsNil - given two set lists, s1, s2, return TRUE if the
                       s1 * s2 = {}
*/

static unsigned int IntersectionIsNil (pge_SetDesc s1, pge_SetDesc s2);

/*
   AddSet - adds a first symbol to a production.
*/

static void AddSet (pge_SetDesc *to, NameKey_Name s);

/*
   OrSet -
*/

static void OrSet (pge_SetDesc *to, pge_SetDesc from);

/*
   CalcFirstFactor -
*/

static void CalcFirstFactor (pge_FactorDesc f, pge_ProductionDesc from, pge_SetDesc *to);

/*
   CalcFirstTerm -
*/

static void CalcFirstTerm (pge_TermDesc t, pge_ProductionDesc from, pge_SetDesc *to);

/*
   CalcFirstExpression -
*/

static void CalcFirstExpression (pge_ExpressionDesc e, pge_ProductionDesc from, pge_SetDesc *to);

/*
   CalcFirstStatement -
*/

static void CalcFirstStatement (pge_StatementDesc s, pge_ProductionDesc from, pge_SetDesc *to);

/*
   CalcFirstProduction - calculates all of the first symbols for the grammer
*/

static void CalcFirstProduction (pge_ProductionDesc p, pge_ProductionDesc from, pge_SetDesc *to);
static void WorkOutFollowFactor (pge_FactorDesc f, pge_SetDesc *followset, pge_SetDesc after);

/*
   WorkOutFollowTerm -
*/

static void WorkOutFollowTerm (pge_TermDesc t, pge_SetDesc *followset, pge_SetDesc after);

/*
   WorkOutFollowExpression -
*/

static void WorkOutFollowExpression (pge_ExpressionDesc e, pge_SetDesc *followset, pge_SetDesc after);

/*
   CollectFollow - collects the follow set from, f, into, to.
*/

static void CollectFollow (pge_SetDesc *to, pge_FollowDesc f);

/*
   CalcFollowFactor -
*/

static void CalcFollowFactor (pge_FactorDesc f, pge_SetDesc after);

/*
   CalcFollowTerm -
*/

static void CalcFollowTerm (pge_TermDesc t, pge_SetDesc after);

/*
   CalcFollowExpression -
*/

static void CalcFollowExpression (pge_ExpressionDesc e, pge_SetDesc after);

/*
   CalcFollowStatement - given a bnf statement generate the follow set.
*/

static void CalcFollowStatement (pge_StatementDesc s);

/*
   CalcFollowProduction -
*/

static void CalcFollowProduction (pge_ProductionDesc p);

/*
   CalcEpsilonFactor -
*/

static void CalcEpsilonFactor (pge_FactorDesc f);

/*
   CalcEpsilonTerm -
*/

static void CalcEpsilonTerm (pge_TermDesc t);

/*
   CalcEpsilonExpression -
*/

static void CalcEpsilonExpression (pge_ExpressionDesc e);

/*
   CalcEpsilonStatement - given a bnf statement generate the follow set.
*/

static void CalcEpsilonStatement (pge_StatementDesc s);

/*
   CalcEpsilonProduction -
*/

static void CalcEpsilonProduction (pge_ProductionDesc p);

/*
   CalcReachEndFactor -
*/

static pge_TraverseResult CalcReachEndFactor (pge_FactorDesc f);

/*
   CalcReachEndTerm -
*/

static pge_TraverseResult CalcReachEndTerm (pge_TermDesc t);

/*
   CalcReachEndExpression -
*/

static void CalcReachEndExpression (pge_ExpressionDesc e);

/*
   CalcReachEndStatement -
*/

static void CalcReachEndStatement (pge_StatementDesc s);

/*
   CalcReachEndStatement -
*/

static void stop (void);

/*
   CalcReachEndProduction -
*/

static void CalcReachEndProduction (pge_ProductionDesc p);

/*
   EmptyFactor -
*/

static unsigned int EmptyFactor (pge_FactorDesc f);

/*
   EmptyTerm - returns TRUE if the term maybe empty.
*/

static unsigned int EmptyTerm (pge_TermDesc t);

/*
   EmptyExpression -
*/

static unsigned int EmptyExpression (pge_ExpressionDesc e);

/*
   EmptyStatement - returns TRUE if statement, s, is empty.
*/

static unsigned int EmptyStatement (pge_StatementDesc s);

/*
   EmptyProduction - returns if production, p, maybe empty.
*/

static unsigned int EmptyProduction (pge_ProductionDesc p);

/*
   EmitFDLNotice -
*/

static void EmitFDLNotice (void);

/*
   EmitRules - generates the BNF rules.
*/

static void EmitRules (void);

/*
   DescribeElement -
*/

static void DescribeElement (unsigned int name);

/*
   EmitInTestStop - construct a test for stop element, name.
*/

static void EmitInTestStop (NameKey_Name name);

/*
   DescribeStopElement -
*/

static void DescribeStopElement (unsigned int name);

/*
   EmitDescribeStop -
*/

static void EmitDescribeStop (void);

/*
   EmitDescribeError -
*/

static void EmitDescribeError (void);

/*
   EmitSetTypes - write out the set types used during error recovery
*/

static void EmitSetTypes (void);

/*
   EmitSupport - generates the support routines.
*/

static void EmitSupport (void);

/*
   DisposeSetDesc - dispose of the set list, s.
*/

static void DisposeSetDesc (pge_SetDesc *s);

/*
   OptionalFactor -
*/

static unsigned int OptionalFactor (pge_FactorDesc f);

/*
   OptionalTerm - returns TRUE if the term maybe empty.
*/

static unsigned int OptionalTerm (pge_TermDesc t);

/*
   OptionalExpression -
*/

static unsigned int OptionalExpression (pge_ExpressionDesc e);

/*
   OptionalStatement - returns FALSE if statement, s, does not have a optional ambiguity.
*/

static unsigned int OptionalStatement (pge_StatementDesc s);

/*
   OptionalProduction -
*/

static unsigned int OptionalProduction (pge_ProductionDesc p);

/*
   CheckFirstFollow -
*/

static unsigned int CheckFirstFollow (pge_FactorDesc f, pge_FactorDesc after);

/*
   ConstrainedEmptyFactor -
*/

static unsigned int ConstrainedEmptyFactor (pge_FactorDesc f);

/*
   ConstrainedEmptyTerm - returns TRUE if the term maybe empty.
*/

static unsigned int ConstrainedEmptyTerm (pge_TermDesc t);

/*
   ConstrainedEmptyExpression -
*/

static unsigned int ConstrainedEmptyExpression (pge_ExpressionDesc e);

/*
   ConstrainedEmptyStatement - returns FALSE if statement, s, does not have a optional ambiguity.
*/

static unsigned int ConstrainedEmptyStatement (pge_StatementDesc s);

/*
   ConstrainedEmptyProduction - returns TRUE if a problem exists with, p.
*/

static unsigned int ConstrainedEmptyProduction (pge_ProductionDesc p);

/*
   TestForLALR1 -
*/

static void TestForLALR1 (pge_ProductionDesc p);

/*
   DoEpsilon - runs the epsilon interrelated rules
*/

static void DoEpsilon (pge_ProductionDesc p);

/*
   CheckComplete - checks that production, p, is complete.
*/

static void CheckComplete (pge_ProductionDesc p);

/*
   PostProcessRules - backpatch the ident to rule definitions and emit comments and code.
*/

static void PostProcessRules (void);

/*
   DisplayHelp - display a summary help and then exit (0).
*/

static void DisplayHelp (void);

/*
   ParseArgs -
*/

static void ParseArgs (void);

/*
   Init - initialize the modules data structures
*/

static void Init (void);

/*
   DescribeStop - issues a message explaining what tokens were expected
*/

static DynamicStrings_String DescribeStop (pge_SetOfStop stopset);

/*
   DescribeError - issues a message explaining what tokens were expected
*/

static void DescribeError (void);

/*
   AddEntry - adds an entry into, t, containing [def:value].
*/

static void AddEntry (SymbolKey_SymbolTree *t, NameKey_Name def, NameKey_Name value);

/*
   Format1 - converts string, src, into, dest, together with encapsulated
             entity, n. It only formats the first %s or %d with n.
*/

static void Format1 (const char *src_, unsigned int _src_high, unsigned int n, char *dest, unsigned int _dest_high);

/*
   WarnError1 -
*/

static void WarnError1 (const char *a_, unsigned int _a_high, unsigned int n);

/*
   PrettyFollow -
*/

static void PrettyFollow (const char *start_, unsigned int _start_high, const char *end_, unsigned int _end_high, pge_FollowDesc f);

/*
   NewFollow - creates a new follow descriptor and returns the data structure.
*/

static pge_FollowDesc NewFollow (void);

/*
   AssignEpsilon - assigns the epsilon value and sets the epsilon to value,
                   providing condition is TRUE.
*/

static void AssignEpsilon (unsigned int condition, pge_FollowDesc f, pge_TraverseResult value);

/*
   GetEpsilon - returns the value of epsilon
*/

static pge_TraverseResult GetEpsilon (pge_FollowDesc f);

/*
   AssignReachEnd - assigns the reachend value providing that, condition, is TRUE.
*/

static void AssignReachEnd (unsigned int condition, pge_FollowDesc f, pge_TraverseResult value);

/*
   GetReachEnd - returns the value of reachend
*/

static pge_TraverseResult GetReachEnd (pge_FollowDesc f);

/*
   AssignFollow - assigns the follow set and sets the calcfollow to TRUE.
*/

static void AssignFollow (pge_FollowDesc f, pge_SetDesc s);

/*
   GetFollow - returns the follow set.
*/

static pge_SetDesc GetFollow (pge_FollowDesc f);

/*
   NewProduction - creates a new production and returns the data structure.
*/

static pge_ProductionDesc NewProduction (void);

/*
   NewFactor -
*/

static pge_FactorDesc NewFactor (void);

/*
   NewTerm - returns a new term.
*/

static pge_TermDesc NewTerm (void);

/*
   NewExpression - returns a new expression.
*/

static pge_ExpressionDesc NewExpression (void);

/*
   NewStatement - returns a new statement.
*/

static pge_StatementDesc NewStatement (void);

/*
   NewSetDesc - creates a new set description and returns the data structure.
*/

static pge_SetDesc NewSetDesc (void);

/*
   NewCodeDesc - creates a new code descriptor and initializes all fields to zero.
*/

static pge_CodeDesc NewCodeDesc (void);

/*
   CodeFragmentPrologue - consumes code text up to a "%" after a newline.
*/

static void CodeFragmentPrologue (void);

/*
   CodeFragmentEpilogue - consumes code text up to a "%" after a newline.
*/

static void CodeFragmentEpilogue (void);

/*
   CodeFragmentDeclaration - consumes code text up to a "%" after a newline.
*/

static void CodeFragmentDeclaration (void);

/*
   GetCodeFragment - collects the code fragment up until ^ %
*/

static void GetCodeFragment (pge_CodeHunk *h);

/*
   WriteCodeHunkList - writes the CodeHunk list in the correct order.
*/

static void WriteCodeHunkList (pge_CodeHunk l);

/*
   WriteIndent - writes, n, spaces.
*/

static void WriteIndent (unsigned int n);

/*
   CheckWrite -
*/

static void CheckWrite (char ch, unsigned int *curpos, unsigned int left, unsigned int *seentext);

/*
   WriteStringIndent - writes a string but it will try and remove upto indent spaces
                       if they exist.
*/

static void WriteStringIndent (const char *a_, unsigned int _a_high, unsigned int indent, unsigned int *curpos, unsigned int left, unsigned int *seentext);

/*
   WriteCodeHunkListIndent - writes the CodeHunk list in the correct order
                             but it removes up to indent spaces if they exist.
*/

static void WriteCodeHunkListIndent (pge_CodeHunk l, unsigned int indent, unsigned int *curpos, unsigned int left, unsigned int *seentext);

/*
   Add - adds a character to a code hunk and creates another code hunk if necessary.
*/

static pge_CodeHunk Add (pge_CodeHunk *p, char ch, unsigned int *i);

/*
   ConsHunk - combine two possible code hunks.
*/

static void ConsHunk (pge_CodeHunk *p, pge_CodeHunk q);

/*
   GetName - returns the next symbol which is checked for a legal name.
*/

static NameKey_Name GetName (void);

/*
   SyntaxError - after a syntax error we skip all tokens up until we reach
                 a stop symbol.
*/

static void SyntaxError (pge_SetOfStop stop);

/*
   SyntaxCheck -
*/

static void SyntaxCheck (pge_SetOfStop stop);

/*
   Expect -
*/

static void Expect (bnflex_TokenType t, pge_SetOfStop stop);

/*
   Ident - error checking varient of Ident
*/

static void Ident (pge_SetOfStop stop);

/*
   Modula2Code - error checking varient of Modula2Code
*/

static void Modula2Code (pge_SetOfStop stop);

/*
   StartModName    := % ModuleName := GetName() ;  ignore begintok  CodeFragmentPrologue % =:
*/

static void StartModName (pge_SetOfStop stop);

/*
   EndModName    :=
*/

static void EndModName (pge_SetOfStop stop);

/*
   DoDeclaration := % CodeFragmentDeclaration % =:
*/

static void DoDeclaration (pge_SetOfStop stop);

/*
   CollectLiteral := 
                     % LastLiteral := GetCurrentToken() ;
                       AdvanceToken ;  %
                     

   first  symbols:literaltok
   
   cannot reachend
*/

static void CollectLiteral (pge_SetOfStop stopset);

/*
   CollectTok := 
                 % CurrentSetDesc := NewSetDesc() ;
                   WITH CurrentSetDesc^ DO
                      type   := tokel ;
                      string := GetCurrentToken() ;
                   END ;
                   IF NOT ContainsSymKey(Values, GetCurrentToken())
                   THEN
                      AddEntry(Values, GetCurrentToken(), LargestValue) ;
                      AddEntry(ReverseValues, Name(LargestValue), GetCurrentToken()) ;
                      AddEntry(Aliases, GetCurrentToken(), GetCurrentToken()) ;
                      AddEntry(ReverseAliases, GetCurrentToken(), GetCurrentToken()) ;
                      INC(LargestValue)
                   END ;
                   AdvanceToken() ;  %
                 

   first  symbols:identtok
   
   cannot reachend
*/

static void CollectTok (pge_SetOfStop stopset);

/*
   DefineToken := 
                  % AddEntry(Aliases, LastLiteral, GetCurrentToken()) ;
                    AddEntry(ReverseAliases, GetCurrentToken(), LastLiteral) ;
                    AddEntry(Values, GetCurrentToken(), LargestValue) ;
                    AddEntry(ReverseValues, Name(LargestValue), GetCurrentToken()) ;
                    INC(LargestValue) ;
                    AdvanceToken ;  %
                  

   first  symbols:identtok
   
   cannot reachend
*/

static void DefineToken (pge_SetOfStop stopset);

/*
   Rules := '%' 'rules' { Defs  } ExtBNF 

   first  symbols:codetok
   
   cannot reachend
*/

static void Rules (pge_SetOfStop stopset);

/*
   Special := Ident 
              % VAR p: ProductionDesc ;  %
              
              % p                           := NewProduction() ;
                p^.statement                := NewStatement() ;
                p^.statement^.followinfo^.calcfollow := TRUE ;
                p^.statement^.followinfo^.epsilon    := false ;
                p^.statement^.followinfo^.reachend   := false ;
                p^.statement^.ident         := CurrentIdent ;
                p^.statement^.expr          := NIL ;
                p^.firstsolved              := TRUE ;
                p^.followinfo^.calcfollow   := TRUE ;
                p^.followinfo^.epsilon      := false ;
                p^.followinfo^.reachend     := false  %
              First Follow [ 'epsilon' 
                             % p^.statement^.followinfo^.epsilon  := true ;   these are not used - but they are displayed when debugging 
                               p^.statement^.followinfo^.reachend := true ;
                               p^.followinfo^.epsilon  := true ;
                               p^.followinfo^.reachend := true
                                %
                              ] [ Literal 
                                  % p^.description := LastLiteral  %
                                   ] 

   first  symbols:identtok
   
   cannot reachend
*/

static void Special (pge_SetOfStop stopset);

/*
   Factor := '%' Modula2Code '%'  | 
             Ident 
             % WITH CurrentFactor^ DO
                  type  := id ;
                  ident := CurrentIdent
               END ;  %
              | Literal 
             % WITH CurrentFactor^ DO
                  type   := lit ;
                  string := LastLiteral ;
                  IF GetSymKey(Aliases, LastLiteral)=NulName
                  THEN
                     WarnError1('no token defined for literal %s', LastLiteral)
                  END
               END ;  %
              | '{' 
             % WITH CurrentFactor^ DO
                  type := mult ;
                  expr := NewExpression() ;
                  CurrentExpression := expr ;
               END ;  %
             Expression '}'  | '[' 
             % WITH CurrentFactor^ DO
                  type := opt ;
                  expr := NewExpression() ;
                  CurrentExpression := expr ;
               END ;  %
             Expression ']'  | '(' 
             % WITH CurrentFactor^ DO
                  type := sub ;
                  expr := NewExpression() ;
                  CurrentExpression := expr ;
               END ;  %
             Expression ')' 

   first  symbols:dquotetok, squotetok, lparatok, lsparatok, lcparatok, identtok, codetok
   
   cannot reachend
*/

static void Factor (pge_SetOfStop stopset);

/*
   Statement := 
                % VAR i: IdentDesc ;  %
                Ident 
                % VAR p: ProductionDesc ;  %
                
                % p := FindDefinition(CurrentIdent^.name) ;
                  IF p=NIL
                  THEN
                     p := NewProduction()
                  ELSE
                     IF NOT ((p^.statement=NIL) OR (p^.statement^.expr=NIL))
                     THEN
                        WarnError1('already declared rule %s', CurrentIdent^.name)
                     END
                  END ;
                  i := CurrentIdent ;  %
                ':=' 
                % VAR e: ExpressionDesc ;  %
                
                % e := NewExpression() ;
                  CurrentExpression := e ;  %
                
                % VAR s: StatementDesc ;  %
                
                % s := NewStatement() ;
                  WITH s^ DO
                     ident := i ;
                     expr  := e
                  END ;  %
                Expression 
                % p^.statement := s ;  %
                '=:' 

   first  symbols:identtok
   
   cannot reachend
*/

static void Statement (pge_SetOfStop stopset);

/*
   Defs := 'special' Special  | 'token' Token  | 
           'error' ErrorProcedures  | 
           'tokenfunc' TokenProcedure  | 
           'symfunc' SymProcedure 

   first  symbols:symfunctok, tfunctok, errortok, tokentok, specialtok
   
   cannot reachend
*/

static void Defs (pge_SetOfStop stopset);

/*
   ExtBNF := 'BNF' { Production  } 'FNB' 

   first  symbols:BNFtok
   
   cannot reachend
*/

static void ExtBNF (pge_SetOfStop stopset);

/*
   Main := Header Decls Footer Rules 

   first  symbols:codetok
   
   cannot reachend
*/

static void Main (pge_SetOfStop stopset);

/*
   Header := '%' 'module' StartModName 

   first  symbols:codetok
   
   cannot reachend
*/

static void Header (pge_SetOfStop stopset);

/*
   Decls := '%' 'declaration' DoDeclaration 

   first  symbols:codetok
   
   cannot reachend
*/

static void Decls (pge_SetOfStop stopset);

/*
   Footer := '%' 'module' EndModName 

   first  symbols:codetok
   
   cannot reachend
*/

static void Footer (pge_SetOfStop stopset);

/*
   First := 'first' '{' { LitOrTokenOrIdent 
                          % WITH CurrentSetDesc^ DO
                               next := TailProduction^.first ;
                            END ;
                            TailProduction^.first := CurrentSetDesc
                             %
                           } '}' 

   first  symbols:firsttok
   
   cannot reachend
*/

static void First (pge_SetOfStop stopset);

/*
   Follow := 'follow' '{' { LitOrTokenOrIdent 
                            % WITH CurrentSetDesc^ DO
                                 next := TailProduction^.followinfo^.follow ;
                              END ;
                              TailProduction^.followinfo^.follow := CurrentSetDesc
                               %
                             } '}' 

   first  symbols:followtok
   
   cannot reachend
*/

static void Follow (pge_SetOfStop stopset);

/*
   LitOrTokenOrIdent := Literal 
                        % CurrentSetDesc := NewSetDesc() ;
                          WITH CurrentSetDesc^ DO
                             type   := litel ;
                             string := LastLiteral ;
                          END ;
                           %
                         | '<' CollectTok '>'  | 
                        Ident 
                        % CurrentSetDesc := NewSetDesc() ;
                          WITH CurrentSetDesc^ DO
                             type   := idel ;
                             ident  := CurrentIdent ;
                          END ;
                           %
                        

   first  symbols:dquotetok, squotetok, identtok, lesstok
   
   cannot reachend
*/

static void LitOrTokenOrIdent (pge_SetOfStop stopset);

/*
   Literal := '"' CollectLiteral '"'  | 
              "'" CollectLiteral "'" 

   first  symbols:squotetok, dquotetok
   
   cannot reachend
*/

static void Literal (pge_SetOfStop stopset);

/*
   Token := Literal DefineToken 

   first  symbols:dquotetok, squotetok
   
   cannot reachend
*/

static void Token (pge_SetOfStop stopset);

/*
   ErrorProcedures := Literal 
                      % ErrorProcArray := LastLiteral  %
                      Literal 
                      % ErrorProcString := LastLiteral  %
                      

   first  symbols:dquotetok, squotetok
   
   cannot reachend
*/

static void ErrorProcedures (pge_SetOfStop stopset);

/*
   TokenProcedure := Literal 
                     % TokenTypeProc := LastLiteral  %
                     

   first  symbols:dquotetok, squotetok
   
   cannot reachend
*/

static void TokenProcedure (pge_SetOfStop stopset);

/*
   SymProcedure := Literal 
                   % SymIsProc := LastLiteral  %
                   

   first  symbols:dquotetok, squotetok
   
   cannot reachend
*/

static void SymProcedure (pge_SetOfStop stopset);

/*
   Production := Statement 

   first  symbols:identtok
   
   cannot reachend
*/

static void Production (pge_SetOfStop stopset);

/*
   Expression := 
                 % VAR t1, t2: TermDesc ;
                       e     : ExpressionDesc ;  %
                 
                 % e := CurrentExpression ;
                   t1 := NewTerm() ;
                   CurrentTerm := t1 ;  %
                 Term 
                 % e^.term := t1 ;  %
                 { '|' 
                   % t2 := NewTerm() ;
                     CurrentTerm := t2  %
                   Term 
                   % t1^.next := t2 ;
                     t1 := t2  %
                    } 

   first  symbols:dquotetok, squotetok, lparatok, lsparatok, lcparatok, identtok, codetok
   
   cannot reachend
*/

static void Expression (pge_SetOfStop stopset);

/*
   Term := 
           % VAR    t1: TermDesc ; f1, f2: FactorDesc ;  %
           
           % CurrentFactor := NewFactor() ;
             f1 := CurrentFactor ;
             t1 := CurrentTerm ;  %
           Factor 
           % t1^.factor := f1 ;
             f2 := NewFactor() ;
             CurrentFactor := f2  %
           { Factor 
             % f1^.next := f2 ;
               f1 := f2 ;
               f2 := NewFactor() ;
               CurrentFactor := f2 ;  %
              } 

   first  symbols:squotetok, dquotetok, codetok, identtok, lcparatok, lsparatok, lparatok
   
   cannot reachend
*/

static void Term (pge_SetOfStop stopset);

/*
   GetDefinitionName - returns the name of the rule inside, p.
*/

static NameKey_Name GetDefinitionName (pge_ProductionDesc p);

/*
   FindDefinition - searches and returns the rule which defines, n.
*/

static pge_ProductionDesc FindDefinition (NameKey_Name n);

/*
   BackPatchIdent - found an ident, i, we must look for the corresponding rule and
                    set the definition accordingly.
*/

static void BackPatchIdent (pge_IdentDesc i);

/*
   BackPatchFactor - runs through the factor looking for an ident
*/

static void BackPatchFactor (pge_FactorDesc f);

/*
   BackPatchTerm - runs through all terms to find idents.
*/

static void BackPatchTerm (pge_TermDesc t);

/*
   BackPatchExpression - runs through the term to find any idents.
*/

static void BackPatchExpression (pge_ExpressionDesc e);

/*
   BackPatchSet -
*/

static void BackPatchSet (pge_SetDesc s);

/*
   BackPatchIdentToDefinitions - search through all the rules and add a link from any ident
                                 to the definition.
*/

static void BackPatchIdentToDefinitions (pge_ProductionDesc d);

/*
   CalculateFirstAndFollow -
*/

static void CalculateFirstAndFollow (pge_ProductionDesc p);

/*
   ForeachRuleDo -
*/

static void ForeachRuleDo (pge_DoProcedure p);

/*
   WhileNotCompleteDo -
*/

static void WhileNotCompleteDo (pge_DoProcedure p);

/*
   NewLine - generate a newline and indent.
*/

static void NewLine (unsigned int Left);

/*
   CheckNewLine -
*/

static void CheckNewLine (unsigned int Left);

/*
   IndentString - writes out a string with a preceeding indent.
*/

static void IndentString (const char *a_, unsigned int _a_high);

/*
   KeyWord - writes out a keywork with optional formatting directives.
*/

static void KeyWord (NameKey_Name n);

/*
   PrettyPara -
*/

static void PrettyPara (const char *c1_, unsigned int _c1_high, const char *c2_, unsigned int _c2_high, pge_ExpressionDesc e, unsigned int Left);

/*
   WriteKeyTexinfo -
*/

static void WriteKeyTexinfo (NameKey_Name s);

/*
   PrettyCommentFactor -
*/

static void PrettyCommentFactor (pge_FactorDesc f, unsigned int Left);

/*
   PeepTerm - returns the length of characters in term.
*/

static unsigned int PeepTerm (pge_TermDesc t);

/*
   PeepExpression - returns the length of the expression.
*/

static unsigned int PeepExpression (pge_ExpressionDesc e);

/*
   PeepFactor - returns the length of character in the factor
*/

static unsigned int PeepFactor (pge_FactorDesc f);

/*
   PrettyCommentTerm -
*/

static void PrettyCommentTerm (pge_TermDesc t, unsigned int Left);

/*
   PrettyCommentExpression -
*/

static void PrettyCommentExpression (pge_ExpressionDesc e, unsigned int Left);

/*
   PrettyCommentStatement -
*/

static void PrettyCommentStatement (pge_StatementDesc s, unsigned int Left);

/*
   PrettyCommentProduction - generates the comment for rule, p.
*/

static void PrettyCommentProduction (pge_ProductionDesc p);

/*
   PrettyPrintProduction - pretty prints the ebnf rule, p.
*/

static void PrettyPrintProduction (pge_ProductionDesc p);

/*
   EmitFileLineTag - emits a line and file tag using the C preprocessor syntax.
*/

static void EmitFileLineTag (unsigned int line);

/*
   EmitRule - generates a comment and code for rule, p.
*/

static void EmitRule (pge_ProductionDesc p);

/*
   CodeCondition -
*/

static void CodeCondition (pge_m2condition m);

/*
   CodeThenDo - codes a "THEN" or "DO" depending upon, m.
*/

static void CodeThenDo (pge_m2condition m);

/*
   CodeElseEnd - builds an ELSE END statement using string, end.
*/

static void CodeElseEnd (const char *end_, unsigned int _end_high, unsigned int consumed, pge_FactorDesc f, unsigned int inopt);

/*
   CodeEnd - codes a "END" depending upon, m.
*/

static void CodeEnd (pge_m2condition m, pge_TermDesc t, unsigned int consumed, pge_FactorDesc f, unsigned int inopt);

/*
   EmitNonVarCode - writes out, code, providing it is not a variable declaration.
*/

static void EmitNonVarCode (pge_CodeDesc code, unsigned int curpos, unsigned int left);

/*
   ChainOn -
*/

static pge_FactorDesc ChainOn (pge_FactorDesc codeStack, pge_FactorDesc f);

/*
   FlushCode -
*/

static void FlushCode (pge_FactorDesc *codeStack);

/*
   CodeFactor -
*/

static void CodeFactor (pge_FactorDesc f, pge_TermDesc t, pge_m2condition l, pge_m2condition n, unsigned int inopt, unsigned int inwhile, unsigned int consumed, pge_FactorDesc codeStack);

/*
   CodeTerm -
*/

static void CodeTerm (pge_TermDesc t, pge_m2condition m, unsigned int inopt, unsigned int inwhile, unsigned int consumed, pge_FactorDesc codeStack);

/*
   CodeExpression -
*/

static void CodeExpression (pge_ExpressionDesc e, pge_m2condition m, unsigned int inopt, unsigned int inwhile, unsigned int consumed, pge_FactorDesc codeStack);

/*
   CodeStatement -
*/

static void CodeStatement (pge_StatementDesc s, pge_m2condition m);

/*
   CodeProduction - only encode grammer rules which are not special.
*/

static void CodeProduction (pge_ProductionDesc p);

/*
   RecoverCondition -
*/

static void RecoverCondition (pge_m2condition m);

/*
   ConditionIndent - returns the number of spaces indentation created via, m.
*/

static unsigned int ConditionIndent (pge_m2condition m);

/*
   WriteGetTokenType - writes out the method of determining the token type.
*/

static void WriteGetTokenType (void);

/*
   NumberOfElements - returns the number of elements in set, to, which lie between low..high
*/

static unsigned int NumberOfElements (pge_SetDesc to, unsigned int low, unsigned int high);

/*
   WriteElement - writes the literal name for element, e.
*/

static void WriteElement (unsigned int e);

/*
   EmitIsInSet - writes out the equivalent of GetTokenType() IN { toset }
*/

static void EmitIsInSet (pge_SetDesc to, NameKey_Name low, NameKey_Name high);

/*
   EmitIsInSubSet - writes out a test to see whether GetTokenype() is in { subset }
*/

static void EmitIsInSubSet (pge_SetDesc to, unsigned int low, unsigned int high);

/*
   EmitIsInFirst -
*/

static void EmitIsInFirst (pge_SetDesc to, pge_m2condition m);
static void FlushRecoverCode (pge_FactorDesc *codeStack);

/*
   RecoverFactor -
*/

static void RecoverFactor (pge_FactorDesc f, pge_m2condition m, pge_FactorDesc codeStack);

/*
   OptExpSeen - returns TRUE if we can see an optional expression in the factor.
                This is not the same as epsilon. Example { '+' } matches epsilon as
                well as { '+' | '-' } but OptExpSeen returns TRUE in the second case
                and FALSE in the first.
*/

static unsigned int OptExpSeen (pge_FactorDesc f);

/*
   RecoverTerm -
*/

static void RecoverTerm (pge_TermDesc t, pge_m2condition new_, pge_m2condition old);

/*
   RecoverExpression -
*/

static void RecoverExpression (pge_ExpressionDesc e, pge_m2condition new_, pge_m2condition old);

/*
   RecoverStatement -
*/

static void RecoverStatement (pge_StatementDesc s, pge_m2condition m);

/*
   EmitFirstFactor - generate a list of all first tokens between the range: low..high.
*/

static void EmitFirstFactor (pge_FactorDesc f, unsigned int low, unsigned int high);

/*
   EmitUsed -
*/

static void EmitUsed (unsigned int wordno);

/*
   EmitStopParameters - generate the stop set.
*/

static void EmitStopParameters (unsigned int FormalParameters);

/*
   IsBetween - returns TRUE if the value of the token, string, is
               in the range: low..high
*/

static unsigned int IsBetween (NameKey_Name string, unsigned int low, unsigned int high);

/*
   IsEmptySet - returns TRUE if no elements exist in set, to, with values, low..high.
*/

static unsigned int IsEmptySet (pge_SetDesc to, unsigned int low, unsigned int high);

/*
   EmitSet - emits the tokens in the set, to, which have values low..high
*/

static void EmitSet (pge_SetDesc to, unsigned int low, unsigned int high);

/*
   EmitSetName - emits the tokens in the set, to, which have values low..high, using
                 their names.
*/

static void EmitSetName (pge_SetDesc to, unsigned int low, unsigned int high);

/*
   EmitStopParametersAndSet - generates the stop parameters together with a set
                              inclusion of all the symbols in set, to.
*/

static void EmitStopParametersAndSet (pge_SetDesc to);

/*
   EmitSetAsParameters - generates the first symbols as parameters to a set function.
*/

static void EmitSetAsParameters (pge_SetDesc to);

/*
   EmitStopParametersAndFollow - generates the stop parameters together with a set
                                 inclusion of all the follow symbols for subsequent
                                 sentances.
*/

static void EmitStopParametersAndFollow (pge_FactorDesc f, pge_m2condition m);

/*
   EmitFirstAsParameters -
*/

static void EmitFirstAsParameters (pge_FactorDesc f);

/*
   RecoverProduction - only encode grammer rules which are not special.
                       Generate error recovery code.
*/

static void RecoverProduction (pge_ProductionDesc p);

/*
   IsWhite - returns TRUE if, ch, is a space or a tab.
*/

static unsigned int IsWhite (char ch);

/*
   FindStr - returns TRUE if, str, was seen inside the code hunk
*/

static unsigned int FindStr (pge_CodeHunk *code, unsigned int *i, const char *str_, unsigned int _str_high);

/*
   WriteUpto -
*/

static void WriteUpto (pge_CodeHunk code, pge_CodeHunk upto, unsigned int limit);

/*
   CheckForVar - checks for any local variables which need to be emitted during
                 this production.
*/

static void CheckForVar (pge_CodeHunk code);

/*
   VarFactor -
*/

static void VarFactor (pge_FactorDesc f);

/*
   VarTerm -
*/

static void VarTerm (pge_TermDesc t);

/*
   VarExpression -
*/

static void VarExpression (pge_ExpressionDesc e);

/*
   VarStatement -
*/

static void VarStatement (pge_StatementDesc s);

/*
   VarProduction - writes out all variable declarations.
*/

static void VarProduction (pge_ProductionDesc p);

/*
   In - returns TRUE if token, s, is already in the set, to.
*/

static unsigned int In (pge_SetDesc to, NameKey_Name s);

/*
   IntersectionIsNil - given two set lists, s1, s2, return TRUE if the
                       s1 * s2 = {}
*/

static unsigned int IntersectionIsNil (pge_SetDesc s1, pge_SetDesc s2);

/*
   AddSet - adds a first symbol to a production.
*/

static void AddSet (pge_SetDesc *to, NameKey_Name s);

/*
   OrSet -
*/

static void OrSet (pge_SetDesc *to, pge_SetDesc from);

/*
   CalcFirstFactor -
*/

static void CalcFirstFactor (pge_FactorDesc f, pge_ProductionDesc from, pge_SetDesc *to);

/*
   CalcFirstTerm -
*/

static void CalcFirstTerm (pge_TermDesc t, pge_ProductionDesc from, pge_SetDesc *to);

/*
   CalcFirstExpression -
*/

static void CalcFirstExpression (pge_ExpressionDesc e, pge_ProductionDesc from, pge_SetDesc *to);

/*
   CalcFirstStatement -
*/

static void CalcFirstStatement (pge_StatementDesc s, pge_ProductionDesc from, pge_SetDesc *to);

/*
   CalcFirstProduction - calculates all of the first symbols for the grammer
*/

static void CalcFirstProduction (pge_ProductionDesc p, pge_ProductionDesc from, pge_SetDesc *to);
static void WorkOutFollowFactor (pge_FactorDesc f, pge_SetDesc *followset, pge_SetDesc after);

/*
   WorkOutFollowTerm -
*/

static void WorkOutFollowTerm (pge_TermDesc t, pge_SetDesc *followset, pge_SetDesc after);

/*
   WorkOutFollowExpression -
*/

static void WorkOutFollowExpression (pge_ExpressionDesc e, pge_SetDesc *followset, pge_SetDesc after);

/*
   CollectFollow - collects the follow set from, f, into, to.
*/

static void CollectFollow (pge_SetDesc *to, pge_FollowDesc f);

/*
   CalcFollowFactor -
*/

static void CalcFollowFactor (pge_FactorDesc f, pge_SetDesc after);

/*
   CalcFollowTerm -
*/

static void CalcFollowTerm (pge_TermDesc t, pge_SetDesc after);

/*
   CalcFollowExpression -
*/

static void CalcFollowExpression (pge_ExpressionDesc e, pge_SetDesc after);

/*
   CalcFollowStatement - given a bnf statement generate the follow set.
*/

static void CalcFollowStatement (pge_StatementDesc s);

/*
   CalcFollowProduction -
*/

static void CalcFollowProduction (pge_ProductionDesc p);

/*
   CalcEpsilonFactor -
*/

static void CalcEpsilonFactor (pge_FactorDesc f);

/*
   CalcEpsilonTerm -
*/

static void CalcEpsilonTerm (pge_TermDesc t);

/*
   CalcEpsilonExpression -
*/

static void CalcEpsilonExpression (pge_ExpressionDesc e);

/*
   CalcEpsilonStatement - given a bnf statement generate the follow set.
*/

static void CalcEpsilonStatement (pge_StatementDesc s);

/*
   CalcEpsilonProduction -
*/

static void CalcEpsilonProduction (pge_ProductionDesc p);

/*
   CalcReachEndFactor -
*/

static pge_TraverseResult CalcReachEndFactor (pge_FactorDesc f);

/*
   CalcReachEndTerm -
*/

static pge_TraverseResult CalcReachEndTerm (pge_TermDesc t);

/*
   CalcReachEndExpression -
*/

static void CalcReachEndExpression (pge_ExpressionDesc e);

/*
   CalcReachEndStatement -
*/

static void CalcReachEndStatement (pge_StatementDesc s);

/*
   CalcReachEndStatement -
*/

static void stop (void);

/*
   CalcReachEndProduction -
*/

static void CalcReachEndProduction (pge_ProductionDesc p);

/*
   EmptyFactor -
*/

static unsigned int EmptyFactor (pge_FactorDesc f);

/*
   EmptyTerm - returns TRUE if the term maybe empty.
*/

static unsigned int EmptyTerm (pge_TermDesc t);

/*
   EmptyExpression -
*/

static unsigned int EmptyExpression (pge_ExpressionDesc e);

/*
   EmptyStatement - returns TRUE if statement, s, is empty.
*/

static unsigned int EmptyStatement (pge_StatementDesc s);

/*
   EmptyProduction - returns if production, p, maybe empty.
*/

static unsigned int EmptyProduction (pge_ProductionDesc p);

/*
   EmitFDLNotice -
*/

static void EmitFDLNotice (void);

/*
   EmitRules - generates the BNF rules.
*/

static void EmitRules (void);

/*
   DescribeElement -
*/

static void DescribeElement (unsigned int name);

/*
   EmitInTestStop - construct a test for stop element, name.
*/

static void EmitInTestStop (NameKey_Name name);

/*
   DescribeStopElement -
*/

static void DescribeStopElement (unsigned int name);

/*
   EmitDescribeStop -
*/

static void EmitDescribeStop (void);

/*
   EmitDescribeError -
*/

static void EmitDescribeError (void);

/*
   EmitSetTypes - write out the set types used during error recovery
*/

static void EmitSetTypes (void);

/*
   EmitSupport - generates the support routines.
*/

static void EmitSupport (void);

/*
   DisposeSetDesc - dispose of the set list, s.
*/

static void DisposeSetDesc (pge_SetDesc *s);

/*
   OptionalFactor -
*/

static unsigned int OptionalFactor (pge_FactorDesc f);

/*
   OptionalTerm - returns TRUE if the term maybe empty.
*/

static unsigned int OptionalTerm (pge_TermDesc t);

/*
   OptionalExpression -
*/

static unsigned int OptionalExpression (pge_ExpressionDesc e);

/*
   OptionalStatement - returns FALSE if statement, s, does not have a optional ambiguity.
*/

static unsigned int OptionalStatement (pge_StatementDesc s);

/*
   OptionalProduction -
*/

static unsigned int OptionalProduction (pge_ProductionDesc p);

/*
   CheckFirstFollow -
*/

static unsigned int CheckFirstFollow (pge_FactorDesc f, pge_FactorDesc after);

/*
   ConstrainedEmptyFactor -
*/

static unsigned int ConstrainedEmptyFactor (pge_FactorDesc f);

/*
   ConstrainedEmptyTerm - returns TRUE if the term maybe empty.
*/

static unsigned int ConstrainedEmptyTerm (pge_TermDesc t);

/*
   ConstrainedEmptyExpression -
*/

static unsigned int ConstrainedEmptyExpression (pge_ExpressionDesc e);

/*
   ConstrainedEmptyStatement - returns FALSE if statement, s, does not have a optional ambiguity.
*/

static unsigned int ConstrainedEmptyStatement (pge_StatementDesc s);

/*
   ConstrainedEmptyProduction - returns TRUE if a problem exists with, p.
*/

static unsigned int ConstrainedEmptyProduction (pge_ProductionDesc p);

/*
   TestForLALR1 -
*/

static void TestForLALR1 (pge_ProductionDesc p);

/*
   DoEpsilon - runs the epsilon interrelated rules
*/

static void DoEpsilon (pge_ProductionDesc p);

/*
   CheckComplete - checks that production, p, is complete.
*/

static void CheckComplete (pge_ProductionDesc p);

/*
   PostProcessRules - backpatch the ident to rule definitions and emit comments and code.
*/

static void PostProcessRules (void);

/*
   DisplayHelp - display a summary help and then exit (0).
*/

static void DisplayHelp (void);

/*
   ParseArgs -
*/

static void ParseArgs (void);

/*
   Init - initialize the modules data structures
*/

static void Init (void);


/*
   DescribeStop - issues a message explaining what tokens were expected
*/

static DynamicStrings_String DescribeStop (pge_SetOfStop stopset)
{
  unsigned int n;
  DynamicStrings_String str;
  DynamicStrings_String message;

  n = 0;
  message = DynamicStrings_InitString ((const char *) "", 0);
  if ((((1 << (bnflex_literaltok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "literal", 7)));
      n += 1;
    }
  if ((((1 << (bnflex_identtok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "identifier", 10)));
      n += 1;
    }
  if ((((1 << (bnflex_FNBtok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "FNB", 3)));
      n += 1;
    }
  if ((((1 << (bnflex_BNFtok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "BNF", 3)));
      n += 1;
    }
  if ((((1 << (bnflex_epsilontok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "epsilon", 7)));
      n += 1;
    }
  if ((((1 << (bnflex_followtok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "follow", 6)));
      n += 1;
    }
  if ((((1 << (bnflex_firsttok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "first", 5)));
      n += 1;
    }
  if ((((1 << (bnflex_specialtok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "special", 7)));
      n += 1;
    }
  if ((((1 << (bnflex_tokentok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "token", 5)));
      n += 1;
    }
  if ((((1 << (bnflex_declarationtok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "declaration", 11)));
      n += 1;
    }
  if ((((1 << (bnflex_endtok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "end", 3)));
      n += 1;
    }
  if ((((1 << (bnflex_rulestok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "rules", 5)));
      n += 1;
    }
  if ((((1 << (bnflex_begintok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "begin", 5)));
      n += 1;
    }
  if ((((1 << (bnflex_moduletok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "module", 6)));
      n += 1;
    }
  if ((((1 << (bnflex_dquotetok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCatChar (DynamicStrings_ConCatChar (DynamicStrings_ConCatChar (DynamicStrings_ConCatChar (DynamicStrings_ConCatChar (message, ' '), '`'), '"'), '\''), ',');
      n += 1;
    }
  if ((((1 << (bnflex_squotetok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCatChar (DynamicStrings_ConCatChar (DynamicStrings_ConCatChar (DynamicStrings_ConCatChar (DynamicStrings_ConCatChar (message, ' '), '"'), '\''), '"'), ',');
      n += 1;
    }
  if ((((1 << (bnflex_symfunctok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "symfunc", 7)));
      n += 1;
    }
  if ((((1 << (bnflex_tfunctok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "tokenfunc", 9)));
      n += 1;
    }
  if ((((1 << (bnflex_errortok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "error", 5)));
      n += 1;
    }
  if ((((1 << (bnflex_gretok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) ">", 1)));
      n += 1;
    }
  if ((((1 << (bnflex_lesstok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "<", 1)));
      n += 1;
    }
  if ((((1 << (bnflex_rparatok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) ")", 1)));
      n += 1;
    }
  if ((((1 << (bnflex_lparatok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "(", 1)));
      n += 1;
    }
  if ((((1 << (bnflex_rcparatok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "}", 1)));
      n += 1;
    }
  if ((((1 << (bnflex_lcparatok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "{", 1)));
      n += 1;
    }
  if ((((1 << (bnflex_rsparatok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "]", 1)));
      n += 1;
    }
  if ((((1 << (bnflex_lsparatok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "[", 1)));
      n += 1;
    }
  if ((((1 << (bnflex_bartok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "|", 1)));
      n += 1;
    }
  if ((((1 << (bnflex_rbecomestok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "=:", 2)));
      n += 1;
    }
  if ((((1 << (bnflex_lbecomestok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) ":=", 2)));
      n += 1;
    }
  if ((((1 << (bnflex_codetok-bnflex_identtok)) & (stopset)) != 0))
    {
      message = DynamicStrings_ConCat (DynamicStrings_ConCatChar (message, ' '), DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "%", 1)));
      n += 1;
    }
  if ((((1 << (bnflex_eoftok-bnflex_identtok)) & (stopset)) != 0))
    {}  /* empty.  */
  /* eoftok has no token name (needed to generate error messages)  */
  if (n == 0)
    {
      str = DynamicStrings_InitString ((const char *) " syntax error", 13);
      message = DynamicStrings_KillString (message);
    }
  else if (n == 1)
    {
      /* avoid dangling else.  */
      str = DynamicStrings_ConCat (message, DynamicStrings_Mark (DynamicStrings_InitString ((const char *) " missing ", 9)));
    }
  else
    {
      /* avoid dangling else.  */
      str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) " expecting one of", 17), message);
      message = DynamicStrings_KillString (message);
    }
  return str;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   DescribeError - issues a message explaining what tokens were expected
*/

static void DescribeError (void)
{
  DynamicStrings_String str;

  str = DynamicStrings_InitString ((const char *) "", 0);
  switch (bnflex_GetCurrentTokenType ())
    {
      case bnflex_literaltok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found literal", 27), DynamicStrings_Mark (str));
        break;

      case bnflex_identtok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found identifier", 30), DynamicStrings_Mark (str));
        break;

      case bnflex_FNBtok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found FNB", 23), DynamicStrings_Mark (str));
        break;

      case bnflex_BNFtok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found BNF", 23), DynamicStrings_Mark (str));
        break;

      case bnflex_epsilontok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found epsilon", 27), DynamicStrings_Mark (str));
        break;

      case bnflex_followtok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found follow", 26), DynamicStrings_Mark (str));
        break;

      case bnflex_firsttok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found first", 25), DynamicStrings_Mark (str));
        break;

      case bnflex_specialtok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found special", 27), DynamicStrings_Mark (str));
        break;

      case bnflex_tokentok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found token", 25), DynamicStrings_Mark (str));
        break;

      case bnflex_declarationtok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found declaration", 31), DynamicStrings_Mark (str));
        break;

      case bnflex_endtok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found end", 23), DynamicStrings_Mark (str));
        break;

      case bnflex_rulestok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found rules", 25), DynamicStrings_Mark (str));
        break;

      case bnflex_begintok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found begin", 25), DynamicStrings_Mark (str));
        break;

      case bnflex_moduletok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found module", 26), DynamicStrings_Mark (str));
        break;

      case bnflex_dquotetok:
        str = DynamicStrings_ConCat (DynamicStrings_ConCatChar (DynamicStrings_ConCatChar (DynamicStrings_InitString ((const char *) "syntax error, found '", 21), '"'), '\''), DynamicStrings_Mark (str));
        break;

      case bnflex_squotetok:
        str = DynamicStrings_ConCat (DynamicStrings_ConCatChar (DynamicStrings_ConCatChar (DynamicStrings_InitString ((const char *) "syntax error, found \"", 21), '\''), '"'), DynamicStrings_Mark (str));
        break;

      case bnflex_symfunctok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found symfunc", 27), DynamicStrings_Mark (str));
        break;

      case bnflex_tfunctok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found tokenfunc", 29), DynamicStrings_Mark (str));
        break;

      case bnflex_errortok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found error", 25), DynamicStrings_Mark (str));
        break;

      case bnflex_gretok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found >", 21), DynamicStrings_Mark (str));
        break;

      case bnflex_lesstok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found <", 21), DynamicStrings_Mark (str));
        break;

      case bnflex_rparatok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found )", 21), DynamicStrings_Mark (str));
        break;

      case bnflex_lparatok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found (", 21), DynamicStrings_Mark (str));
        break;

      case bnflex_rcparatok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found }", 21), DynamicStrings_Mark (str));
        break;

      case bnflex_lcparatok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found {", 21), DynamicStrings_Mark (str));
        break;

      case bnflex_rsparatok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found ]", 21), DynamicStrings_Mark (str));
        break;

      case bnflex_lsparatok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found [", 21), DynamicStrings_Mark (str));
        break;

      case bnflex_bartok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found |", 21), DynamicStrings_Mark (str));
        break;

      case bnflex_rbecomestok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found =:", 22), DynamicStrings_Mark (str));
        break;

      case bnflex_lbecomestok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found :=", 22), DynamicStrings_Mark (str));
        break;

      case bnflex_codetok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found %", 21), DynamicStrings_Mark (str));
        break;

      case bnflex_eoftok:
        str = DynamicStrings_ConCat (DynamicStrings_InitString ((const char *) "syntax error, found ", 20), DynamicStrings_Mark (str));
        break;


      default:
        break;
    }
  PushBackInput_WarnString (str);
}


/*
   AddEntry - adds an entry into, t, containing [def:value].
*/

static void AddEntry (SymbolKey_SymbolTree *t, NameKey_Name def, NameKey_Name value)
{
  if (SymbolKey_ContainsSymKey ((*t), def))
    {
      WarnError1 ((const char *) "already seen a definition for token '%s'", 40, def);
    }
  else
    {
      SymbolKey_PutSymKey ((*t), def, value);
    }
}


/*
   Format1 - converts string, src, into, dest, together with encapsulated
             entity, n. It only formats the first %s or %d with n.
*/

static void Format1 (const char *src_, unsigned int _src_high, unsigned int n, char *dest, unsigned int _dest_high)
{
  typedef struct Format1__T12_a Format1__T12;

  struct Format1__T12_a { char array[MaxString+1]; };
  unsigned int HighSrc;
  unsigned int HighDest;
  unsigned int i;
  unsigned int j;
  Format1__T12 str;
  char src[_src_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (src, src_, _src_high+1);

  HighSrc = StrLib_StrLen ((const char *) src, _src_high);
  HighDest = _dest_high;
  i = 0;
  j = 0;
  while ((((i < HighSrc) && (src[i] != ASCII_nul)) && (j < HighDest)) && (src[i] != '%'))
    {
      dest[j] = src[i];
      i += 1;
      j += 1;
    }
  if ((((i+1) < HighSrc) && (src[i] == '%')) && (j < HighDest))
    {
      /* avoid gcc warning by using compound statement even if not strictly necessary.  */
      if (src[i+1] == 's')
        {
          dest[j] = ASCII_nul;
          NameKey_GetKey (n, (char *) &str.array[0], MaxString);
          StrLib_StrConCat ((const char *) dest, _dest_high, (const char *) &str.array[0], MaxString, (char *) dest, _dest_high);
          j = StrLib_StrLen ((const char *) dest, _dest_high);
          i += 2;
        }
      else if (src[i+1] == 'd')
        {
          /* avoid dangling else.  */
          dest[j] = ASCII_nul;
          NumberIO_CardToStr (n, 0, (char *) &str.array[0], MaxString);
          StrLib_StrConCat ((const char *) dest, _dest_high, (const char *) &str.array[0], MaxString, (char *) dest, _dest_high);
          j = StrLib_StrLen ((const char *) dest, _dest_high);
          i += 2;
        }
      else
        {
          /* avoid dangling else.  */
          dest[j] = src[i];
          i += 1;
          j += 1;
        }
    }
  /* and finish off copying src into dest  */
  while (((i < HighSrc) && (src[i] != ASCII_nul)) && (j < HighDest))
    {
      dest[j] = src[i];
      i += 1;
      j += 1;
    }
  if (j < HighDest)
    {
      dest[j] = ASCII_nul;
    }
}


/*
   WarnError1 -
*/

static void WarnError1 (const char *a_, unsigned int _a_high, unsigned int n)
{
  typedef struct WarnError1__T13_a WarnError1__T13;

  struct WarnError1__T13_a { char array[MaxString+1]; };
  WarnError1__T13 line;
  char a[_a_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);

  Format1 ((const char *) a, _a_high, n, (char *) &line.array[0], MaxString);
  PushBackInput_WarnError ((const char *) &line.array[0], MaxString);
}


/*
   PrettyFollow -
*/

static void PrettyFollow (const char *start_, unsigned int _start_high, const char *end_, unsigned int _end_high, pge_FollowDesc f)
{
  char start[_start_high+1];
  char end[_end_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (start, start_, _start_high+1);
  memcpy (end, end_, _end_high+1);

  if (Debugging)
    {
      Output_WriteString ((const char *) start, _start_high);
      if (f != NULL)
        {
          if (f->calcfollow)
            {
              Output_WriteString ((const char *) "followset defined as:", 21);
              EmitSet (f->follow, static_cast<unsigned int> (0), static_cast<unsigned int> (0));
            }
          switch (f->reachend)
            {
              case pge_true:
                Output_WriteString ((const char *) " [E]", 4);
                break;

              case pge_false:
                Output_WriteString ((const char *) " [C]", 4);
                break;

              case pge_unknown:
                Output_WriteString ((const char *) " [U]", 4);
                break;


              default:
                break;
            }
          switch (f->epsilon)
            {
              case pge_true:
                Output_WriteString ((const char *) " [e]", 4);
                break;

              case pge_false:
                break;

              case pge_unknown:
                Output_WriteString ((const char *) " [u]", 4);
                break;


              default:
                break;
            }
        }
      Output_WriteString ((const char *) end, _end_high);
    }
}


/*
   NewFollow - creates a new follow descriptor and returns the data structure.
*/

static pge_FollowDesc NewFollow (void)
{
  pge_FollowDesc f;

  Storage_ALLOCATE ((void **) &f, sizeof (pge__T6));
  f->follow = NULL;
  f->reachend = pge_unknown;
  f->epsilon = pge_unknown;
  return f;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   AssignEpsilon - assigns the epsilon value and sets the epsilon to value,
                   providing condition is TRUE.
*/

static void AssignEpsilon (unsigned int condition, pge_FollowDesc f, pge_TraverseResult value)
{
  if ((condition && (value != pge_unknown)) && (f->epsilon == pge_unknown))
    {
      f->epsilon = value;
      Finished = FALSE;
    }
}


/*
   GetEpsilon - returns the value of epsilon
*/

static pge_TraverseResult GetEpsilon (pge_FollowDesc f)
{
  if (f == NULL)
    {
      Debug_Halt ((const char *) "why is the follow info NIL?", 27, 596, (const char *) "m2/gm2-auto/pge.mod", 19);
    }
  else
    {
      return f->epsilon;
    }
  ReturnException ("m2/gm2-auto/pge.mod", 1, 7);
  __builtin_unreachable ();
}


/*
   AssignReachEnd - assigns the reachend value providing that, condition, is TRUE.
*/

static void AssignReachEnd (unsigned int condition, pge_FollowDesc f, pge_TraverseResult value)
{
  if (condition)
    {
      if ((f->reachend == pge_unknown) && (value != pge_unknown))
        {
          f->reachend = value;
          Finished = FALSE;
        }
    }
}


/*
   GetReachEnd - returns the value of reachend
*/

static pge_TraverseResult GetReachEnd (pge_FollowDesc f)
{
  if (f == NULL)
    {
      Debug_Halt ((const char *) "why is the follow info NIL?", 27, 630, (const char *) "m2/gm2-auto/pge.mod", 19);
    }
  else
    {
      return f->reachend;
    }
  ReturnException ("m2/gm2-auto/pge.mod", 1, 7);
  __builtin_unreachable ();
}


/*
   AssignFollow - assigns the follow set and sets the calcfollow to TRUE.
*/

static void AssignFollow (pge_FollowDesc f, pge_SetDesc s)
{
  if (f->calcfollow)
    {
      Debug_Halt ((const char *) "why are we reassigning this follow set?", 39, 646, (const char *) "m2/gm2-auto/pge.mod", 19);
    }
  f->follow = s;
  f->calcfollow = TRUE;
}


/*
   GetFollow - returns the follow set.
*/

static pge_SetDesc GetFollow (pge_FollowDesc f)
{
  if (f == NULL)
    {
      Debug_Halt ((const char *) "why is the follow info NIL?", 27, 662, (const char *) "m2/gm2-auto/pge.mod", 19);
    }
  else
    {
      if (f->calcfollow)
        {
          return f->follow;
        }
      else
        {
          Debug_Halt ((const char *) "not calculated the follow set yet..", 35, 669, (const char *) "m2/gm2-auto/pge.mod", 19);
        }
    }
  ReturnException ("m2/gm2-auto/pge.mod", 1, 7);
  __builtin_unreachable ();
}


/*
   NewProduction - creates a new production and returns the data structure.
*/

static pge_ProductionDesc NewProduction (void)
{
  pge_ProductionDesc p;

  Storage_ALLOCATE ((void **) &p, sizeof (pge__T2));
  if (TailProduction != NULL)
    {
      TailProduction->next = p;
    }
  TailProduction = p;
  if (HeadProduction == NULL)
    {
      HeadProduction = p;
    }
  p->next = NULL;
  p->statement = NULL;
  p->first = NULL;
  p->firstsolved = FALSE;
  p->followinfo = NewFollow ();
  p->line = PushBackInput_GetCurrentLine ();
  p->description = NameKey_NulName;
  return p;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   NewFactor -
*/

static pge_FactorDesc NewFactor (void)
{
  pge_FactorDesc f;

  Storage_ALLOCATE ((void **) &f, sizeof (pge__T5));
  f->next = NULL;
  f->followinfo = NewFollow ();
  f->line = PushBackInput_GetCurrentLine ();
  return f;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   NewTerm - returns a new term.
*/

static pge_TermDesc NewTerm (void)
{
  pge_TermDesc t;

  Storage_ALLOCATE ((void **) &t, sizeof (pge_termdesc));
  t->factor = NULL;
  t->followinfo = NewFollow ();
  t->next = NULL;
  t->line = PushBackInput_GetCurrentLine ();
  return t;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   NewExpression - returns a new expression.
*/

static pge_ExpressionDesc NewExpression (void)
{
  pge_ExpressionDesc e;

  Storage_ALLOCATE ((void **) &e, sizeof (pge__T4));
  e->term = NULL;
  e->followinfo = NewFollow ();
  e->line = PushBackInput_GetCurrentLine ();
  return e;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   NewStatement - returns a new statement.
*/

static pge_StatementDesc NewStatement (void)
{
  pge_StatementDesc s;

  Storage_ALLOCATE ((void **) &s, sizeof (pge__T3));
  s->ident = NULL;
  s->expr = NULL;
  s->followinfo = NewFollow ();
  s->line = PushBackInput_GetCurrentLine ();
  return s;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   NewSetDesc - creates a new set description and returns the data structure.
*/

static pge_SetDesc NewSetDesc (void)
{
  pge_SetDesc s;

  Storage_ALLOCATE ((void **) &s, sizeof (pge__T7));
  s->next = NULL;
  return s;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   NewCodeDesc - creates a new code descriptor and initializes all fields to zero.
*/

static pge_CodeDesc NewCodeDesc (void)
{
  pge_CodeDesc c;

  Storage_ALLOCATE ((void **) &c, sizeof (pge__T8));
  c->code = NULL;
  c->indent = 0;
  c->line = PushBackInput_GetCurrentLine ();
  return c;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   CodeFragmentPrologue - consumes code text up to a "%" after a newline.
*/

static void CodeFragmentPrologue (void)
{
  LinePrologue = PushBackInput_GetCurrentLine ();
  GetCodeFragment (&CodePrologue);
}


/*
   CodeFragmentEpilogue - consumes code text up to a "%" after a newline.
*/

static void CodeFragmentEpilogue (void)
{
  LineEpilogue = PushBackInput_GetCurrentLine ();
  GetCodeFragment (&CodeEpilogue);
}


/*
   CodeFragmentDeclaration - consumes code text up to a "%" after a newline.
*/

static void CodeFragmentDeclaration (void)
{
  LineDeclaration = PushBackInput_GetCurrentLine ();
  GetCodeFragment (&CodeDeclaration);
}


/*
   GetCodeFragment - collects the code fragment up until ^ %
*/

static void GetCodeFragment (pge_CodeHunk *h)
{
  unsigned int i;
  char ch;

  (*h) = NULL;
  i = 0;
  while (((bnflex_PutChar (bnflex_GetChar ())) != '%') && ((bnflex_PutChar (bnflex_GetChar ())) != ASCII_nul))
    {
      do {
        while (((bnflex_PutChar (bnflex_GetChar ())) != ASCII_nul) && ((bnflex_PutChar (bnflex_GetChar ())) != ASCII_lf))
          {
            (*h) = Add (h, bnflex_GetChar (), &i);
          }
        if ((bnflex_PutChar (bnflex_GetChar ())) == ASCII_lf)
          {
            /* consume line feed  */
            (*h) = Add (h, bnflex_GetChar (), &i);
            ch = bnflex_PutChar (ASCII_lf);
          }
        else if ((bnflex_PutChar (bnflex_GetChar ())) == ASCII_nul)
          {
            /* avoid dangling else.  */
            ch = bnflex_PutChar (ASCII_nul);
            ch = bnflex_PutChar (ASCII_lf);
          }
        else
          {
            /* avoid dangling else.  */
            ch = bnflex_PutChar (bnflex_PutChar (bnflex_GetChar ()));
          }
      } while (! ((bnflex_GetChar ()) == ASCII_lf));
    }
  if ((bnflex_PutChar (bnflex_GetChar ())) == '%')
    {
      (*h) = Add (h, ASCII_nul, &i);
      ch = bnflex_PutChar (' ');  /* to give the following token % a delimiter infront of it  */
      bnflex_AdvanceToken ();  /* to give the following token % a delimiter infront of it  */
    }
  else
    {
      PushBackInput_WarnError ((const char *) "expecting % to terminate code fragment, found end of file", 57);
    }
}


/*
   WriteCodeHunkList - writes the CodeHunk list in the correct order.
*/

static void WriteCodeHunkList (pge_CodeHunk l)
{
  if (l != NULL)
    {
      OnLineStart = FALSE;
      /* recursion  */
      WriteCodeHunkList (l->next);
      Output_WriteString ((const char *) &l->codetext.array[0], MaxCodeHunkLength);
    }
}


/*
   WriteIndent - writes, n, spaces.
*/

static void WriteIndent (unsigned int n)
{
  while (n > 0)
    {
      Output_Write (' ');
      n -= 1;
    }
  OnLineStart = FALSE;
}


/*
   CheckWrite -
*/

static void CheckWrite (char ch, unsigned int *curpos, unsigned int left, unsigned int *seentext)
{
  if (ch == ASCII_lf)
    {
      NewLine (left);
      (*curpos) = 0;
      (*seentext) = FALSE;
    }
  else
    {
      Output_Write (ch);
      (*curpos) += 1;
    }
}


/*
   WriteStringIndent - writes a string but it will try and remove upto indent spaces
                       if they exist.
*/

static void WriteStringIndent (const char *a_, unsigned int _a_high, unsigned int indent, unsigned int *curpos, unsigned int left, unsigned int *seentext)
{
  unsigned int l;
  unsigned int i;
  char a[_a_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);

  i = 0;
  l = StrLib_StrLen ((const char *) a, _a_high);
  while (i < l)
    {
      if ((*seentext))
        {
          CheckWrite (a[i], curpos, left, seentext);
        }
      else
        {
          if (a[i] == ' ')
            {
              /* ignore space for now  */
              (*curpos) += 1;
            }
          else
            {
              if ((*curpos) >= indent)
                {
                  WriteIndent ((*curpos)-indent);
                }
              (*seentext) = TRUE;
              CheckWrite (a[i], curpos, left, seentext);
            }
        }
      i += 1;
    }
}


/*
   WriteCodeHunkListIndent - writes the CodeHunk list in the correct order
                             but it removes up to indent spaces if they exist.
*/

static void WriteCodeHunkListIndent (pge_CodeHunk l, unsigned int indent, unsigned int *curpos, unsigned int left, unsigned int *seentext)
{
  if (l != NULL)
    {
      /* recursion  */
      WriteCodeHunkListIndent (l->next, indent, curpos, left, seentext);
      WriteStringIndent ((const char *) &l->codetext.array[0], MaxCodeHunkLength, indent, curpos, left, seentext);
    }
}


/*
   Add - adds a character to a code hunk and creates another code hunk if necessary.
*/

static pge_CodeHunk Add (pge_CodeHunk *p, char ch, unsigned int *i)
{
  pge_CodeHunk q;

  if (((*p) == NULL) || ((*i) > MaxCodeHunkLength))
    {
      Storage_ALLOCATE ((void **) &q, sizeof (pge__T9));
      q->next = (*p);
      q->codetext.array[0] = ch;
      (*i) = 1;
      return q;
    }
  else
    {
      (*p)->codetext.array[(*i)] = ch;
      (*i) += 1;
      return (*p);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   ConsHunk - combine two possible code hunks.
*/

static void ConsHunk (pge_CodeHunk *p, pge_CodeHunk q)
{
  pge_CodeHunk r;

  if ((*p) != NULL)
    {
      r = q;
      while (r->next != NULL)
        {
          r = r->next;
        }
      r->next = (*p);
    }
  (*p) = q;
}


/*
   GetName - returns the next symbol which is checked for a legal name.
*/

static NameKey_Name GetName (void)
{
  NameKey_Name name;

  if (bnflex_IsReserved (bnflex_GetCurrentToken ()))
    {
      PushBackInput_WarnError ((const char *) "expecting a name and found a reserved word", 42);
      bnflex_AdvanceToken ();  /* move on to another token  */
      return NameKey_NulName;  /* move on to another token  */
    }
  else
    {
      name = bnflex_GetCurrentToken ();
      bnflex_AdvanceToken ();
      return name;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   SyntaxError - after a syntax error we skip all tokens up until we reach
                 a stop symbol.
*/

static void SyntaxError (pge_SetOfStop stop)
{
  DescribeError ();
  if (Debugging)
    {
      StrIO_WriteLn ();
      StrIO_WriteString ((const char *) "skipping token *** ", 19);
    }
  while (! ((((1 << (bnflex_GetCurrentTokenType ()-bnflex_identtok)) & (stop)) != 0)))
    {
      bnflex_AdvanceToken ();
    }
  if (Debugging)
    {
      StrIO_WriteString ((const char *) " ***", 4);
      StrIO_WriteLn ();
    }
  WasNoError = FALSE;
}


/*
   SyntaxCheck -
*/

static void SyntaxCheck (pge_SetOfStop stop)
{
  if (! ((((1 << (bnflex_GetCurrentTokenType ()-bnflex_identtok)) & (stop)) != 0)))
    {
      SyntaxError (stop);
    }
}


/*
   Expect -
*/

static void Expect (bnflex_TokenType t, pge_SetOfStop stop)
{
  if ((bnflex_GetCurrentTokenType ()) == t)
    {
      bnflex_AdvanceToken ();
    }
  else
    {
      SyntaxError (stop);
    }
  SyntaxCheck (stop);
}


/*
   Ident - error checking varient of Ident
*/

static void Ident (pge_SetOfStop stop)
{
  if ((bnflex_GetCurrentTokenType ()) == bnflex_identtok)
    {
      Storage_ALLOCATE ((void **) &CurrentIdent, sizeof (pge__T1));
      CurrentIdent->definition = NULL;
      CurrentIdent->name = GetName ();
      CurrentIdent->line = PushBackInput_GetCurrentLine ();
    }
}


/*
   Modula2Code - error checking varient of Modula2Code
*/

static void Modula2Code (pge_SetOfStop stop)
{
  pge_CodeHunk p;
  unsigned int i;
  unsigned int quote;
  unsigned int line;
  unsigned int position;

  line = PushBackInput_GetCurrentLine ();
  bnflex_PushBackToken (bnflex_GetCurrentToken ());
  position = PushBackInput_GetColumnPosition ();
  p = NULL;
  bnflex_SkipWhite ();
  while (((bnflex_PutChar (bnflex_GetChar ())) != '%') && ((bnflex_PutChar (bnflex_GetChar ())) != ASCII_nul))
    {
      if ((bnflex_PutChar (bnflex_GetChar ())) == '"')
        {
          /* avoid dangling else.  */
          do {
            p = Add (&p, bnflex_GetChar (), &i);
          } while (! (((bnflex_PutChar (bnflex_GetChar ())) == '"') || ((bnflex_PutChar (bnflex_GetChar ())) == ASCII_nul)));
          p = Add (&p, '"', &i);
          if (((bnflex_PutChar (bnflex_GetChar ())) == '"') && ((bnflex_GetChar ()) == '"'))
            {}  /* empty.  */
        }
      else if ((bnflex_PutChar (bnflex_GetChar ())) == '\'')
        {
          /* avoid dangling else.  */
          do {
            p = Add (&p, bnflex_GetChar (), &i);
          } while (! (((bnflex_PutChar (bnflex_GetChar ())) == '\'') || ((bnflex_PutChar (bnflex_GetChar ())) == ASCII_nul)));
          p = Add (&p, '\'', &i);
          if (((bnflex_PutChar (bnflex_GetChar ())) == '\'') && ((bnflex_GetChar ()) == '\''))
            {}  /* empty.  */
        }
      else if (((bnflex_PutChar (bnflex_GetChar ())) == '\\') && ((bnflex_GetChar ()) == '\\'))
        {
          /* avoid dangling else.  */
          p = Add (&p, bnflex_GetChar (), &i);
        }
      else if ((bnflex_PutChar (bnflex_GetChar ())) != '%')
        {
          /* avoid dangling else.  */
          p = Add (&p, bnflex_GetChar (), &i);
        }
    }
  p = Add (&p, ASCII_nul, &i);
  CurrentFactor->type = pge_m2;
  CurrentFactor->code = NewCodeDesc ();
  CurrentFactor->code->code = p;
  CurrentFactor->code->indent = position;
  if ((bnflex_PutChar (' ')) == ' ')
    {}  /* empty.  */
  bnflex_AdvanceToken ();  /* read the next token ready for the parser  */
  if (! WasNoError)  /* read the next token ready for the parser  */
    {
      WarnError1 ((const char *) "error probably occurred before the start of inline code on line %d", 66, line);
    }
}


/*
   StartModName    := % ModuleName := GetName() ;  ignore begintok  CodeFragmentPrologue % =:
*/

static void StartModName (pge_SetOfStop stop)
{
  ModuleName = GetName ();
  CodeFragmentPrologue ();
}


/*
   EndModName    :=
*/

static void EndModName (pge_SetOfStop stop)
{
  if (ModuleName != (GetName ()))
    {
      PushBackInput_WarnError ((const char *) "expecting same module name at end as beginning", 46);
    }
  /* ignore endtok as it consumes the token afterwards  */
  CodeFragmentEpilogue ();
}


/*
   DoDeclaration := % CodeFragmentDeclaration % =:
*/

static void DoDeclaration (pge_SetOfStop stop)
{
  if (ModuleName != (GetName ()))
    {
      PushBackInput_WarnError ((const char *) "expecting same module name in declaration as in the beginning", 61);
    }
  /* ignore begintok as it consumes the token afterwards  */
  CodeFragmentDeclaration ();
}


/*
   CollectLiteral := 
                     % LastLiteral := GetCurrentToken() ;
                       AdvanceToken ;  %
                     

   first  symbols:literaltok
   
   cannot reachend
*/

static void CollectLiteral (pge_SetOfStop stopset)
{
  LastLiteral = bnflex_GetCurrentToken ();  /*   */
  bnflex_AdvanceToken ();
}


/*
   CollectTok := 
                 % CurrentSetDesc := NewSetDesc() ;
                   WITH CurrentSetDesc^ DO
                      type   := tokel ;
                      string := GetCurrentToken() ;
                   END ;
                   IF NOT ContainsSymKey(Values, GetCurrentToken())
                   THEN
                      AddEntry(Values, GetCurrentToken(), LargestValue) ;
                      AddEntry(ReverseValues, Name(LargestValue), GetCurrentToken()) ;
                      AddEntry(Aliases, GetCurrentToken(), GetCurrentToken()) ;
                      AddEntry(ReverseAliases, GetCurrentToken(), GetCurrentToken()) ;
                      INC(LargestValue)
                   END ;
                   AdvanceToken() ;  %
                 

   first  symbols:identtok
   
   cannot reachend
*/

static void CollectTok (pge_SetOfStop stopset)
{
  CurrentSetDesc = NewSetDesc ();  /*   */
  CurrentSetDesc->type = pge_tokel;
  CurrentSetDesc->string = bnflex_GetCurrentToken ();
  if (! (SymbolKey_ContainsSymKey (Values, bnflex_GetCurrentToken ())))
    {
      AddEntry (&Values, bnflex_GetCurrentToken (), LargestValue);
      AddEntry (&ReverseValues, (NameKey_Name) (LargestValue), bnflex_GetCurrentToken ());
      AddEntry (&Aliases, bnflex_GetCurrentToken (), bnflex_GetCurrentToken ());
      AddEntry (&ReverseAliases, bnflex_GetCurrentToken (), bnflex_GetCurrentToken ());
      LargestValue += 1;
    }
  bnflex_AdvanceToken ();
}


/*
   DefineToken := 
                  % AddEntry(Aliases, LastLiteral, GetCurrentToken()) ;
                    AddEntry(ReverseAliases, GetCurrentToken(), LastLiteral) ;
                    AddEntry(Values, GetCurrentToken(), LargestValue) ;
                    AddEntry(ReverseValues, Name(LargestValue), GetCurrentToken()) ;
                    INC(LargestValue) ;
                    AdvanceToken ;  %
                  

   first  symbols:identtok
   
   cannot reachend
*/

static void DefineToken (pge_SetOfStop stopset)
{
  AddEntry (&Aliases, LastLiteral, bnflex_GetCurrentToken ());  /*   */
  AddEntry (&ReverseAliases, bnflex_GetCurrentToken (), LastLiteral);
  AddEntry (&Values, bnflex_GetCurrentToken (), LargestValue);
  AddEntry (&ReverseValues, (NameKey_Name) (LargestValue), bnflex_GetCurrentToken ());
  LargestValue += 1;
  bnflex_AdvanceToken ();
}


/*
   Rules := '%' 'rules' { Defs  } ExtBNF 

   first  symbols:codetok
   
   cannot reachend
*/

static void Rules (pge_SetOfStop stopset)
{
  Expect (bnflex_codetok, stopset|(pge_SetOfStop) ((1 << (bnflex_rulestok-bnflex_identtok))));
  Expect (bnflex_rulestok, stopset|(pge_SetOfStop) ((1 << (bnflex_symfunctok-bnflex_identtok)) | (1 << (bnflex_tfunctok-bnflex_identtok)) | (1 << (bnflex_errortok-bnflex_identtok)) | (1 << (bnflex_tokentok-bnflex_identtok)) | (1 << (bnflex_specialtok-bnflex_identtok)) | (1 << (bnflex_BNFtok-bnflex_identtok))));
  while ((((1 << (bnflex_GetCurrentTokenType ())) & ((unsigned int) ((1 << (bnflex_specialtok)) | (1 << (bnflex_tokentok)) | (1 << (bnflex_errortok)) | (1 << (bnflex_tfunctok)) | (1 << (bnflex_symfunctok))))) != 0))
    {
      Defs (stopset|(pge_SetOfStop) ((1 << (bnflex_BNFtok-bnflex_identtok)) | (1 << (bnflex_specialtok-bnflex_identtok)) | (1 << (bnflex_tokentok-bnflex_identtok)) | (1 << (bnflex_errortok-bnflex_identtok)) | (1 << (bnflex_tfunctok-bnflex_identtok)) | (1 << (bnflex_symfunctok-bnflex_identtok))));
    }
   /* while  */
  ExtBNF (stopset);
}


/*
   Special := Ident 
              % VAR p: ProductionDesc ;  %
              
              % p                           := NewProduction() ;
                p^.statement                := NewStatement() ;
                p^.statement^.followinfo^.calcfollow := TRUE ;
                p^.statement^.followinfo^.epsilon    := false ;
                p^.statement^.followinfo^.reachend   := false ;
                p^.statement^.ident         := CurrentIdent ;
                p^.statement^.expr          := NIL ;
                p^.firstsolved              := TRUE ;
                p^.followinfo^.calcfollow   := TRUE ;
                p^.followinfo^.epsilon      := false ;
                p^.followinfo^.reachend     := false  %
              First Follow [ 'epsilon' 
                             % p^.statement^.followinfo^.epsilon  := true ;   these are not used - but they are displayed when debugging 
                               p^.statement^.followinfo^.reachend := true ;
                               p^.followinfo^.epsilon  := true ;
                               p^.followinfo^.reachend := true
                                %
                              ] [ Literal 
                                  % p^.description := LastLiteral  %
                                   ] 

   first  symbols:identtok
   
   cannot reachend
*/

static void Special (pge_SetOfStop stopset)
{
  pge_ProductionDesc p;

  Ident (stopset|(pge_SetOfStop) ((1 << (bnflex_firsttok-bnflex_identtok))));
  p = NewProduction ();
  p->statement = NewStatement ();
  p->statement->followinfo->calcfollow = TRUE;
  p->statement->followinfo->epsilon = pge_false;
  p->statement->followinfo->reachend = pge_false;
  p->statement->ident = CurrentIdent;
  p->statement->expr = NULL;
  p->firstsolved = TRUE;
  p->followinfo->calcfollow = TRUE;
  p->followinfo->epsilon = pge_false;
  p->followinfo->reachend = pge_false;
  First (stopset|(pge_SetOfStop) ((1 << (bnflex_followtok-bnflex_identtok))));
  Follow (stopset|(pge_SetOfStop) ((1 << (bnflex_epsilontok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok))));
  if ((bnflex_GetCurrentTokenType ()) == bnflex_epsilontok)
    {
      Expect (bnflex_epsilontok, stopset|(pge_SetOfStop) ((1 << (bnflex_dquotetok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok))));
      p->statement->followinfo->epsilon = pge_true;  /* these are not used - but they are displayed when debugging  */
      p->statement->followinfo->reachend = pge_true;  /* these are not used - but they are displayed when debugging  */
      p->followinfo->epsilon = pge_true;
      p->followinfo->reachend = pge_true;
    }
  if ((((1 << (bnflex_GetCurrentTokenType ())) & ((unsigned int) ((1 << (bnflex_dquotetok)) | (1 << (bnflex_squotetok))))) != 0))
    {
      Literal (stopset);
      p->description = LastLiteral;
    }
}


/*
   Factor := '%' Modula2Code '%'  | 
             Ident 
             % WITH CurrentFactor^ DO
                  type  := id ;
                  ident := CurrentIdent
               END ;  %
              | Literal 
             % WITH CurrentFactor^ DO
                  type   := lit ;
                  string := LastLiteral ;
                  IF GetSymKey(Aliases, LastLiteral)=NulName
                  THEN
                     WarnError1('no token defined for literal %s', LastLiteral)
                  END
               END ;  %
              | '{' 
             % WITH CurrentFactor^ DO
                  type := mult ;
                  expr := NewExpression() ;
                  CurrentExpression := expr ;
               END ;  %
             Expression '}'  | '[' 
             % WITH CurrentFactor^ DO
                  type := opt ;
                  expr := NewExpression() ;
                  CurrentExpression := expr ;
               END ;  %
             Expression ']'  | '(' 
             % WITH CurrentFactor^ DO
                  type := sub ;
                  expr := NewExpression() ;
                  CurrentExpression := expr ;
               END ;  %
             Expression ')' 

   first  symbols:dquotetok, squotetok, lparatok, lsparatok, lcparatok, identtok, codetok
   
   cannot reachend
*/

static void Factor (pge_SetOfStop stopset)
{
  if ((bnflex_GetCurrentTokenType ()) == bnflex_codetok)
    {
      Expect (bnflex_codetok, stopset);
      Modula2Code (stopset|(pge_SetOfStop) ((1 << (bnflex_codetok-bnflex_identtok))));
      Expect (bnflex_codetok, stopset);
    }
  else if ((bnflex_GetCurrentTokenType ()) == bnflex_identtok)
    {
      /* avoid dangling else.  */
      Ident (stopset);
      CurrentFactor->type = pge_id;
      CurrentFactor->ident = CurrentIdent;
    }
  else if ((((1 << (bnflex_GetCurrentTokenType ())) & ((unsigned int) ((1 << (bnflex_dquotetok)) | (1 << (bnflex_squotetok))))) != 0))
    {
      /* avoid dangling else.  */
      Literal (stopset);
      CurrentFactor->type = pge_lit;
      CurrentFactor->string = LastLiteral;
      if ((SymbolKey_GetSymKey (Aliases, LastLiteral)) == NameKey_NulName)
        {
          WarnError1 ((const char *) "no token defined for literal %s", 31, LastLiteral);
        }
    }
  else if ((bnflex_GetCurrentTokenType ()) == bnflex_lcparatok)
    {
      /* avoid dangling else.  */
      Expect (bnflex_lcparatok, stopset|(pge_SetOfStop) ((1 << (bnflex_lparatok-bnflex_identtok)) | (1 << (bnflex_lsparatok-bnflex_identtok)) | (1 << (bnflex_lcparatok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok)) | (1 << (bnflex_codetok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok))));
      CurrentFactor->type = pge_mult;
      CurrentFactor->expr = NewExpression ();
      CurrentExpression = CurrentFactor->expr;
      Expression (stopset|(pge_SetOfStop) ((1 << (bnflex_rcparatok-bnflex_identtok))));
      Expect (bnflex_rcparatok, stopset);
    }
  else if ((bnflex_GetCurrentTokenType ()) == bnflex_lsparatok)
    {
      /* avoid dangling else.  */
      Expect (bnflex_lsparatok, stopset|(pge_SetOfStop) ((1 << (bnflex_lparatok-bnflex_identtok)) | (1 << (bnflex_lsparatok-bnflex_identtok)) | (1 << (bnflex_lcparatok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok)) | (1 << (bnflex_codetok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok))));
      CurrentFactor->type = pge_opt;
      CurrentFactor->expr = NewExpression ();
      CurrentExpression = CurrentFactor->expr;
      Expression (stopset|(pge_SetOfStop) ((1 << (bnflex_rsparatok-bnflex_identtok))));
      Expect (bnflex_rsparatok, stopset);
    }
  else if ((bnflex_GetCurrentTokenType ()) == bnflex_lparatok)
    {
      /* avoid dangling else.  */
      Expect (bnflex_lparatok, stopset|(pge_SetOfStop) ((1 << (bnflex_lparatok-bnflex_identtok)) | (1 << (bnflex_lsparatok-bnflex_identtok)) | (1 << (bnflex_lcparatok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok)) | (1 << (bnflex_codetok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok))));
      CurrentFactor->type = pge_sub;
      CurrentFactor->expr = NewExpression ();
      CurrentExpression = CurrentFactor->expr;
      Expression (stopset|(pge_SetOfStop) ((1 << (bnflex_rparatok-bnflex_identtok))));
      Expect (bnflex_rparatok, stopset);
    }
  else
    {
      /* avoid dangling else.  */
      PushBackInput_WarnError ((const char *) "expecting one of: ( [ { \" single quote identifier %", 51);
    }
}


/*
   Statement := 
                % VAR i: IdentDesc ;  %
                Ident 
                % VAR p: ProductionDesc ;  %
                
                % p := FindDefinition(CurrentIdent^.name) ;
                  IF p=NIL
                  THEN
                     p := NewProduction()
                  ELSE
                     IF NOT ((p^.statement=NIL) OR (p^.statement^.expr=NIL))
                     THEN
                        WarnError1('already declared rule %s', CurrentIdent^.name)
                     END
                  END ;
                  i := CurrentIdent ;  %
                ':=' 
                % VAR e: ExpressionDesc ;  %
                
                % e := NewExpression() ;
                  CurrentExpression := e ;  %
                
                % VAR s: StatementDesc ;  %
                
                % s := NewStatement() ;
                  WITH s^ DO
                     ident := i ;
                     expr  := e
                  END ;  %
                Expression 
                % p^.statement := s ;  %
                '=:' 

   first  symbols:identtok
   
   cannot reachend
*/

static void Statement (pge_SetOfStop stopset)
{
  pge_IdentDesc i;
  pge_ProductionDesc p;
  pge_ExpressionDesc e;
  pge_StatementDesc s;

  Ident (stopset|(pge_SetOfStop) ((1 << (bnflex_lbecomestok-bnflex_identtok))));
  p = FindDefinition (CurrentIdent->name);
  if (p == NULL)
    {
      p = NewProduction ();
    }
  else
    {
      if (! ((p->statement == NULL) || (p->statement->expr == NULL)))
        {
          WarnError1 ((const char *) "already declared rule %s", 24, CurrentIdent->name);
        }
    }
  i = CurrentIdent;
  Expect (bnflex_lbecomestok, stopset|(pge_SetOfStop) ((1 << (bnflex_lparatok-bnflex_identtok)) | (1 << (bnflex_lsparatok-bnflex_identtok)) | (1 << (bnflex_lcparatok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok)) | (1 << (bnflex_codetok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok))));
  e = NewExpression ();
  CurrentExpression = e;
  s = NewStatement ();
  s->ident = i;
  s->expr = e;
  Expression (stopset|(pge_SetOfStop) ((1 << (bnflex_rbecomestok-bnflex_identtok))));
  p->statement = s;
  Expect (bnflex_rbecomestok, stopset);
}


/*
   Defs := 'special' Special  | 'token' Token  | 
           'error' ErrorProcedures  | 
           'tokenfunc' TokenProcedure  | 
           'symfunc' SymProcedure 

   first  symbols:symfunctok, tfunctok, errortok, tokentok, specialtok
   
   cannot reachend
*/

static void Defs (pge_SetOfStop stopset)
{
  if ((bnflex_GetCurrentTokenType ()) == bnflex_specialtok)
    {
      Expect (bnflex_specialtok, stopset|(pge_SetOfStop) ((1 << (bnflex_identtok-bnflex_identtok))));
      Special (stopset);
    }
  else if ((bnflex_GetCurrentTokenType ()) == bnflex_tokentok)
    {
      /* avoid dangling else.  */
      Expect (bnflex_tokentok, stopset|(pge_SetOfStop) ((1 << (bnflex_dquotetok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok))));
      Token (stopset);
    }
  else if ((bnflex_GetCurrentTokenType ()) == bnflex_errortok)
    {
      /* avoid dangling else.  */
      Expect (bnflex_errortok, stopset|(pge_SetOfStop) ((1 << (bnflex_dquotetok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok))));
      ErrorProcedures (stopset);
    }
  else if ((bnflex_GetCurrentTokenType ()) == bnflex_tfunctok)
    {
      /* avoid dangling else.  */
      Expect (bnflex_tfunctok, stopset|(pge_SetOfStop) ((1 << (bnflex_dquotetok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok))));
      TokenProcedure (stopset);
    }
  else if ((bnflex_GetCurrentTokenType ()) == bnflex_symfunctok)
    {
      /* avoid dangling else.  */
      Expect (bnflex_symfunctok, stopset|(pge_SetOfStop) ((1 << (bnflex_dquotetok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok))));
      SymProcedure (stopset);
    }
  else
    {
      /* avoid dangling else.  */
      PushBackInput_WarnError ((const char *) "expecting one of: symfunc tokenfunc error token special", 55);
    }
}


/*
   ExtBNF := 'BNF' { Production  } 'FNB' 

   first  symbols:BNFtok
   
   cannot reachend
*/

static void ExtBNF (pge_SetOfStop stopset)
{
  Expect (bnflex_BNFtok, stopset|(pge_SetOfStop) ((1 << (bnflex_FNBtok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok))));
  while ((bnflex_GetCurrentTokenType ()) == bnflex_identtok)
    {
      Production (stopset|(pge_SetOfStop) ((1 << (bnflex_FNBtok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok))));
    }
   /* while  */
  Expect (bnflex_FNBtok, stopset);
}


/*
   Main := Header Decls Footer Rules 

   first  symbols:codetok
   
   cannot reachend
*/

static void Main (pge_SetOfStop stopset)
{
  Header (stopset|(pge_SetOfStop) ((1 << (bnflex_codetok-bnflex_identtok))));
  Decls (stopset|(pge_SetOfStop) ((1 << (bnflex_codetok-bnflex_identtok))));
  Footer (stopset|(pge_SetOfStop) ((1 << (bnflex_codetok-bnflex_identtok))));
  Rules (stopset);
}


/*
   Header := '%' 'module' StartModName 

   first  symbols:codetok
   
   cannot reachend
*/

static void Header (pge_SetOfStop stopset)
{
  Expect (bnflex_codetok, stopset|(pge_SetOfStop) ((1 << (bnflex_moduletok-bnflex_identtok))));
  Expect (bnflex_moduletok, stopset|(pge_SetOfStop) ((1 << (bnflex_identtok-bnflex_identtok))));
  StartModName (stopset);
}


/*
   Decls := '%' 'declaration' DoDeclaration 

   first  symbols:codetok
   
   cannot reachend
*/

static void Decls (pge_SetOfStop stopset)
{
  Expect (bnflex_codetok, stopset|(pge_SetOfStop) ((1 << (bnflex_declarationtok-bnflex_identtok))));
  Expect (bnflex_declarationtok, stopset|(pge_SetOfStop) ((1 << (bnflex_identtok-bnflex_identtok))));
  DoDeclaration (stopset);
}


/*
   Footer := '%' 'module' EndModName 

   first  symbols:codetok
   
   cannot reachend
*/

static void Footer (pge_SetOfStop stopset)
{
  Expect (bnflex_codetok, stopset|(pge_SetOfStop) ((1 << (bnflex_moduletok-bnflex_identtok))));
  Expect (bnflex_moduletok, stopset|(pge_SetOfStop) ((1 << (bnflex_identtok-bnflex_identtok))));
  EndModName (stopset);
}


/*
   First := 'first' '{' { LitOrTokenOrIdent 
                          % WITH CurrentSetDesc^ DO
                               next := TailProduction^.first ;
                            END ;
                            TailProduction^.first := CurrentSetDesc
                             %
                           } '}' 

   first  symbols:firsttok
   
   cannot reachend
*/

static void First (pge_SetOfStop stopset)
{
  Expect (bnflex_firsttok, stopset|(pge_SetOfStop) ((1 << (bnflex_lcparatok-bnflex_identtok))));
  Expect (bnflex_lcparatok, stopset|(pge_SetOfStop) ((1 << (bnflex_rcparatok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok)) | (1 << (bnflex_lesstok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok))));
  while ((((1 << (bnflex_GetCurrentTokenType ())) & ((unsigned int) ((1 << (bnflex_lesstok)) | (1 << (bnflex_identtok)) | (1 << (bnflex_squotetok)) | (1 << (bnflex_dquotetok))))) != 0))
    {
      LitOrTokenOrIdent (stopset|(pge_SetOfStop) ((1 << (bnflex_rcparatok-bnflex_identtok)) | (1 << (bnflex_lesstok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok))));
      CurrentSetDesc->next = TailProduction->first;
      TailProduction->first = CurrentSetDesc;
    }
   /* while  */
  Expect (bnflex_rcparatok, stopset);
}


/*
   Follow := 'follow' '{' { LitOrTokenOrIdent 
                            % WITH CurrentSetDesc^ DO
                                 next := TailProduction^.followinfo^.follow ;
                              END ;
                              TailProduction^.followinfo^.follow := CurrentSetDesc
                               %
                             } '}' 

   first  symbols:followtok
   
   cannot reachend
*/

static void Follow (pge_SetOfStop stopset)
{
  Expect (bnflex_followtok, stopset|(pge_SetOfStop) ((1 << (bnflex_lcparatok-bnflex_identtok))));
  Expect (bnflex_lcparatok, stopset|(pge_SetOfStop) ((1 << (bnflex_rcparatok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok)) | (1 << (bnflex_lesstok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok))));
  while ((((1 << (bnflex_GetCurrentTokenType ())) & ((unsigned int) ((1 << (bnflex_lesstok)) | (1 << (bnflex_identtok)) | (1 << (bnflex_squotetok)) | (1 << (bnflex_dquotetok))))) != 0))
    {
      LitOrTokenOrIdent (stopset|(pge_SetOfStop) ((1 << (bnflex_rcparatok-bnflex_identtok)) | (1 << (bnflex_lesstok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok))));
      CurrentSetDesc->next = TailProduction->followinfo->follow;
      TailProduction->followinfo->follow = CurrentSetDesc;
    }
   /* while  */
  Expect (bnflex_rcparatok, stopset);
}


/*
   LitOrTokenOrIdent := Literal 
                        % CurrentSetDesc := NewSetDesc() ;
                          WITH CurrentSetDesc^ DO
                             type   := litel ;
                             string := LastLiteral ;
                          END ;
                           %
                         | '<' CollectTok '>'  | 
                        Ident 
                        % CurrentSetDesc := NewSetDesc() ;
                          WITH CurrentSetDesc^ DO
                             type   := idel ;
                             ident  := CurrentIdent ;
                          END ;
                           %
                        

   first  symbols:dquotetok, squotetok, identtok, lesstok
   
   cannot reachend
*/

static void LitOrTokenOrIdent (pge_SetOfStop stopset)
{
  if ((((1 << (bnflex_GetCurrentTokenType ())) & ((unsigned int) ((1 << (bnflex_dquotetok)) | (1 << (bnflex_squotetok))))) != 0))
    {
      Literal (stopset);
      CurrentSetDesc = NewSetDesc ();
      CurrentSetDesc->type = pge_litel;
      CurrentSetDesc->string = LastLiteral;
    }
  else if ((bnflex_GetCurrentTokenType ()) == bnflex_lesstok)
    {
      /* avoid dangling else.  */
      Expect (bnflex_lesstok, stopset|(pge_SetOfStop) ((1 << (bnflex_identtok-bnflex_identtok))));
      CollectTok (stopset|(pge_SetOfStop) ((1 << (bnflex_gretok-bnflex_identtok))));
      Expect (bnflex_gretok, stopset);
    }
  else if ((bnflex_GetCurrentTokenType ()) == bnflex_identtok)
    {
      /* avoid dangling else.  */
      Ident (stopset);
      CurrentSetDesc = NewSetDesc ();
      CurrentSetDesc->type = pge_idel;
      CurrentSetDesc->ident = CurrentIdent;
    }
  else
    {
      /* avoid dangling else.  */
      PushBackInput_WarnError ((const char *) "expecting one of: identifier < \" single quote", 45);
    }
}


/*
   Literal := '"' CollectLiteral '"'  | 
              "'" CollectLiteral "'" 

   first  symbols:squotetok, dquotetok
   
   cannot reachend
*/

static void Literal (pge_SetOfStop stopset)
{
  if ((bnflex_GetCurrentTokenType ()) == bnflex_dquotetok)
    {
      Expect (bnflex_dquotetok, stopset|(pge_SetOfStop) ((1 << (bnflex_literaltok-bnflex_identtok))));
      CollectLiteral (stopset|(pge_SetOfStop) ((1 << (bnflex_dquotetok-bnflex_identtok))));
      Expect (bnflex_dquotetok, stopset);
    }
  else if ((bnflex_GetCurrentTokenType ()) == bnflex_squotetok)
    {
      /* avoid dangling else.  */
      Expect (bnflex_squotetok, stopset|(pge_SetOfStop) ((1 << (bnflex_literaltok-bnflex_identtok))));
      CollectLiteral (stopset|(pge_SetOfStop) ((1 << (bnflex_squotetok-bnflex_identtok))));
      Expect (bnflex_squotetok, stopset);
    }
  else
    {
      /* avoid dangling else.  */
      PushBackInput_WarnError ((const char *) "expecting one of: single quote \"", 32);
    }
}


/*
   Token := Literal DefineToken 

   first  symbols:dquotetok, squotetok
   
   cannot reachend
*/

static void Token (pge_SetOfStop stopset)
{
  Literal (stopset|(pge_SetOfStop) ((1 << (bnflex_identtok-bnflex_identtok))));
  DefineToken (stopset);
}


/*
   ErrorProcedures := Literal 
                      % ErrorProcArray := LastLiteral  %
                      Literal 
                      % ErrorProcString := LastLiteral  %
                      

   first  symbols:dquotetok, squotetok
   
   cannot reachend
*/

static void ErrorProcedures (pge_SetOfStop stopset)
{
  Literal (stopset|(pge_SetOfStop) ((1 << (bnflex_squotetok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok))));
  ErrorProcArray = LastLiteral;
  Literal (stopset);
  ErrorProcString = LastLiteral;
}


/*
   TokenProcedure := Literal 
                     % TokenTypeProc := LastLiteral  %
                     

   first  symbols:dquotetok, squotetok
   
   cannot reachend
*/

static void TokenProcedure (pge_SetOfStop stopset)
{
  Literal (stopset);
  TokenTypeProc = LastLiteral;
}


/*
   SymProcedure := Literal 
                   % SymIsProc := LastLiteral  %
                   

   first  symbols:dquotetok, squotetok
   
   cannot reachend
*/

static void SymProcedure (pge_SetOfStop stopset)
{
  Literal (stopset);
  SymIsProc = LastLiteral;
}


/*
   Production := Statement 

   first  symbols:identtok
   
   cannot reachend
*/

static void Production (pge_SetOfStop stopset)
{
  Statement (stopset);
}


/*
   Expression := 
                 % VAR t1, t2: TermDesc ;
                       e     : ExpressionDesc ;  %
                 
                 % e := CurrentExpression ;
                   t1 := NewTerm() ;
                   CurrentTerm := t1 ;  %
                 Term 
                 % e^.term := t1 ;  %
                 { '|' 
                   % t2 := NewTerm() ;
                     CurrentTerm := t2  %
                   Term 
                   % t1^.next := t2 ;
                     t1 := t2  %
                    } 

   first  symbols:dquotetok, squotetok, lparatok, lsparatok, lcparatok, identtok, codetok
   
   cannot reachend
*/

static void Expression (pge_SetOfStop stopset)
{
  pge_TermDesc t1;
  pge_TermDesc t2;
  pge_ExpressionDesc e;

  e = CurrentExpression;
  t1 = NewTerm ();
  CurrentTerm = t1;
  Term (stopset|(pge_SetOfStop) ((1 << (bnflex_bartok-bnflex_identtok))));
  e->term = t1;
  while ((bnflex_GetCurrentTokenType ()) == bnflex_bartok)
    {
      Expect (bnflex_bartok, stopset|(pge_SetOfStop) ((1 << (bnflex_codetok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok)) | (1 << (bnflex_lcparatok-bnflex_identtok)) | (1 << (bnflex_lsparatok-bnflex_identtok)) | (1 << (bnflex_lparatok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok))));
      t2 = NewTerm ();
      CurrentTerm = t2;
      Term (stopset|(pge_SetOfStop) ((1 << (bnflex_bartok-bnflex_identtok))));
      t1->next = t2;
      t1 = t2;
    }
   /* while  */
}


/*
   Term := 
           % VAR    t1: TermDesc ; f1, f2: FactorDesc ;  %
           
           % CurrentFactor := NewFactor() ;
             f1 := CurrentFactor ;
             t1 := CurrentTerm ;  %
           Factor 
           % t1^.factor := f1 ;
             f2 := NewFactor() ;
             CurrentFactor := f2  %
           { Factor 
             % f1^.next := f2 ;
               f1 := f2 ;
               f2 := NewFactor() ;
               CurrentFactor := f2 ;  %
              } 

   first  symbols:squotetok, dquotetok, codetok, identtok, lcparatok, lsparatok, lparatok
   
   cannot reachend
*/

static void Term (pge_SetOfStop stopset)
{
  pge_TermDesc t1;
  pge_FactorDesc f1;
  pge_FactorDesc f2;

  CurrentFactor = NewFactor ();
  f1 = CurrentFactor;
  t1 = CurrentTerm;
  Factor (stopset|(pge_SetOfStop) ((1 << (bnflex_lparatok-bnflex_identtok)) | (1 << (bnflex_lsparatok-bnflex_identtok)) | (1 << (bnflex_lcparatok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok)) | (1 << (bnflex_codetok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok))));
  t1->factor = f1;
  f2 = NewFactor ();
  CurrentFactor = f2;
  while ((((1 << (bnflex_GetCurrentTokenType ())) & ((unsigned int) ((1 << (bnflex_codetok)) | (1 << (bnflex_identtok)) | (1 << (bnflex_lcparatok)) | (1 << (bnflex_lsparatok)) | (1 << (bnflex_lparatok)) | (1 << (bnflex_squotetok)) | (1 << (bnflex_dquotetok))))) != 0))
    {
      Factor (stopset|(pge_SetOfStop) ((1 << (bnflex_codetok-bnflex_identtok)) | (1 << (bnflex_identtok-bnflex_identtok)) | (1 << (bnflex_lcparatok-bnflex_identtok)) | (1 << (bnflex_lsparatok-bnflex_identtok)) | (1 << (bnflex_lparatok-bnflex_identtok)) | (1 << (bnflex_squotetok-bnflex_identtok)) | (1 << (bnflex_dquotetok-bnflex_identtok))));
      f1->next = f2;
      f1 = f2;
      f2 = NewFactor ();
      CurrentFactor = f2;
    }
   /* while  */
}


/*
   GetDefinitionName - returns the name of the rule inside, p.
*/

static NameKey_Name GetDefinitionName (pge_ProductionDesc p)
{
  if (p != NULL)
    {
      if ((p->statement != NULL) && (p->statement->ident != NULL))
        {
          return p->statement->ident->name;
        }
    }
  return NameKey_NulName;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   FindDefinition - searches and returns the rule which defines, n.
*/

static pge_ProductionDesc FindDefinition (NameKey_Name n)
{
  pge_ProductionDesc p;
  pge_ProductionDesc f;

  p = HeadProduction;
  f = NULL;
  while (p != NULL)
    {
      if ((GetDefinitionName (p)) == n)
        {
          /* avoid gcc warning by using compound statement even if not strictly necessary.  */
          if (f == NULL)
            {
              f = p;
            }
          else
            {
              StrIO_WriteString ((const char *) "multiple definition for rule: ", 30);
              NameKey_WriteKey (n);
              StrIO_WriteLn ();
            }
        }
      p = p->next;
    }
  return f;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   BackPatchIdent - found an ident, i, we must look for the corresponding rule and
                    set the definition accordingly.
*/

static void BackPatchIdent (pge_IdentDesc i)
{
  if (i != NULL)
    {
      i->definition = FindDefinition (i->name);
      if (i->definition == NULL)
        {
          WarnError1 ((const char *) "unable to find production %s", 28, i->name);
          WasNoError = FALSE;
        }
    }
}


/*
   BackPatchFactor - runs through the factor looking for an ident
*/

static void BackPatchFactor (pge_FactorDesc f)
{
  while (f != NULL)
    {
      switch (f->type)
        {
          case pge_id:
            BackPatchIdent (f->ident);
            break;

          case pge_sub:
          case pge_opt:
          case pge_mult:
            BackPatchExpression (f->expr);
            break;


          default:
            break;
        }
      f = f->next;
    }
}


/*
   BackPatchTerm - runs through all terms to find idents.
*/

static void BackPatchTerm (pge_TermDesc t)
{
  while (t != NULL)
    {
      BackPatchFactor (t->factor);
      t = t->next;
    }
}


/*
   BackPatchExpression - runs through the term to find any idents.
*/

static void BackPatchExpression (pge_ExpressionDesc e)
{
  if (e != NULL)
    {
      BackPatchTerm (e->term);
    }
}


/*
   BackPatchSet -
*/

static void BackPatchSet (pge_SetDesc s)
{
  while (s != NULL)
    {
      switch (s->type)
        {
          case pge_idel:
            BackPatchIdent (s->ident);
            break;


          default:
            break;
        }
      s = s->next;
    }
}


/*
   BackPatchIdentToDefinitions - search through all the rules and add a link from any ident
                                 to the definition.
*/

static void BackPatchIdentToDefinitions (pge_ProductionDesc d)
{
  if ((d != NULL) && (d->statement != NULL))
    {
      BackPatchExpression (d->statement->expr);
    }
}


/*
   CalculateFirstAndFollow -
*/

static void CalculateFirstAndFollow (pge_ProductionDesc p)
{
  if (Debugging)
    {
      StrIO_WriteLn ();
      NameKey_WriteKey (p->statement->ident->name);
      StrIO_WriteLn ();
      StrIO_WriteString ((const char *) "  calculating first", 19);
    }
  CalcFirstProduction (p, p, &p->first);
  BackPatchSet (p->first);
  if (Debugging)
    {
      StrIO_WriteString ((const char *) "  calculating follow set", 24);
    }
  if (p->followinfo->follow == NULL)
    {
      CalcFollowProduction (p);
    }
  BackPatchSet (p->followinfo->follow);
}


/*
   ForeachRuleDo -
*/

static void ForeachRuleDo (pge_DoProcedure p)
{
  CurrentProduction = HeadProduction;
  while (CurrentProduction != NULL)
    {
      (*p.proc) (CurrentProduction);
      CurrentProduction = CurrentProduction->next;
    }
}


/*
   WhileNotCompleteDo -
*/

static void WhileNotCompleteDo (pge_DoProcedure p)
{
  do {
    Finished = TRUE;
    ForeachRuleDo (p);
  } while (! (Finished));
}


/*
   NewLine - generate a newline and indent.
*/

static void NewLine (unsigned int Left)
{
  Output_WriteLn ();
  BeginningOfLine = TRUE;
  Indent = 0;
  while (Indent < Left)
    {
      Output_Write (' ');
      Indent += 1;
    }
}


/*
   CheckNewLine -
*/

static void CheckNewLine (unsigned int Left)
{
  if (Indent == Left)
    {
      Left = BaseNewLine;
    }
  if (Indent > BaseRightMargin)
    {
      NewLine (Left);
    }
}


/*
   IndentString - writes out a string with a preceeding indent.
*/

static void IndentString (const char *a_, unsigned int _a_high)
{
  unsigned int i;
  char a[_a_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);

  i = 0;
  while (i < Indent)
    {
      Output_Write (' ');
      i += 1;
    }
  Output_WriteString ((const char *) a, _a_high);
  LastLineNo = 0;
}


/*
   KeyWord - writes out a keywork with optional formatting directives.
*/

static void KeyWord (NameKey_Name n)
{
  if (KeywordFormatting)
    {
      Output_WriteString ((const char *) "{%K", 3);
      if (((n == (NameKey_MakeKey ((const char *) "}", 1))) || (n == (NameKey_MakeKey ((const char *) "{", 1)))) || (n == (NameKey_MakeKey ((const char *) "%", 1))))
        {
          Output_Write ('%');  /* escape }, { or %  */
        }
      Output_WriteKey (n);
      Output_Write ('}');
    }
  else
    {
      Output_WriteKey (n);
    }
}


/*
   PrettyPara -
*/

static void PrettyPara (const char *c1_, unsigned int _c1_high, const char *c2_, unsigned int _c2_high, pge_ExpressionDesc e, unsigned int Left)
{
  char c1[_c1_high+1];
  char c2[_c2_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (c1, c1_, _c1_high+1);
  memcpy (c2, c2_, _c2_high+1);

  Output_WriteString ((const char *) c1, _c1_high);
  Indent += StrLib_StrLen ((const char *) c1, _c1_high);
  Left = Indent;
  PrettyCommentExpression (e, Left);
  Output_WriteString ((const char *) c2, _c2_high);
  Indent += StrLib_StrLen ((const char *) c2, _c2_high);
}


/*
   WriteKeyTexinfo -
*/

static void WriteKeyTexinfo (NameKey_Name s)
{
  DynamicStrings_String ds;
  char ch;
  unsigned int i;
  unsigned int l;

  if (Texinfo)
    {
      ds = DynamicStrings_InitStringCharStar (NameKey_KeyToCharStar (s));
      l = DynamicStrings_Length (ds);
      i = 0;
      while (i < l)
        {
          ch = DynamicStrings_char (ds, static_cast<int> (i));
          if ((ch == '{') || (ch == '}'))
            {
              Output_Write ('@');
            }
          Output_Write (ch);
          i += 1;
        }
    }
  else
    {
      Output_WriteKey (s);
    }
}


/*
   PrettyCommentFactor -
*/

static void PrettyCommentFactor (pge_FactorDesc f, unsigned int Left)
{
  unsigned int curpos;
  unsigned int seentext;

  while (f != NULL)
    {
      CheckNewLine (Left);
      switch (f->type)
        {
          case pge_id:
            Output_WriteKey (f->ident->name);
            Output_WriteString ((const char *) " ", 1);
            Indent += (NameKey_LengthKey (f->ident->name))+1;
            break;

          case pge_lit:
            if ((NameKey_MakeKey ((const char *) "'", 1)) == f->string)
              {
                Output_Write ('"');
                WriteKeyTexinfo (f->string);
                Output_WriteString ((const char *) "\" ", 2);
              }
            else
              {
                Output_Write ('\'');
                WriteKeyTexinfo (f->string);
                Output_WriteString ((const char *) "' ", 2);
              }
            Indent += (NameKey_LengthKey (f->string))+3;
            break;

          case pge_sub:
            PrettyPara ((const char *) "( ", 2, (const char *) " ) ", 3, f->expr, Left);
            break;

          case pge_opt:
            PrettyPara ((const char *) "[ ", 2, (const char *) " ] ", 3, f->expr, Left);
            break;

          case pge_mult:
            if (Texinfo)
              {
                PrettyPara ((const char *) "@{ ", 3, (const char *) " @} ", 4, f->expr, Left);
              }
            else
              {
                PrettyPara ((const char *) "{ ", 2, (const char *) " } ", 3, f->expr, Left);
              }
            break;

          case pge_m2:
            if (EmitCode)
              {
                NewLine (Left);
                Output_WriteString ((const char *) "% ", 2);
                seentext = FALSE;
                curpos = 0;
                WriteCodeHunkListIndent (f->code->code, f->code->indent, &curpos, Left+2, &seentext);
                Output_WriteString ((const char *) " %", 2);
                NewLine (Left);
              }
            break;


          default:
            break;
        }
      PrettyFollow ((const char *) "<f:", 3, (const char *) ":f>", 3, f->followinfo);
      f = f->next;
    }
}


/*
   PeepTerm - returns the length of characters in term.
*/

static unsigned int PeepTerm (pge_TermDesc t)
{
  unsigned int l;

  l = 0;
  while (t != NULL)
    {
      l += PeepFactor (t->factor);
      if (t->next != NULL)
        {
          l += 3;
        }
      t = t->next;
    }
  return l;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   PeepExpression - returns the length of the expression.
*/

static unsigned int PeepExpression (pge_ExpressionDesc e)
{
  if (e == NULL)
    {
      return 0;
    }
  else
    {
      return PeepTerm (e->term);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   PeepFactor - returns the length of character in the factor
*/

static unsigned int PeepFactor (pge_FactorDesc f)
{
  unsigned int l;

  l = 0;
  while (f != NULL)
    {
      switch (f->type)
        {
          case pge_id:
            l += (NameKey_LengthKey (f->ident->name))+1;
            break;

          case pge_lit:
            l += (NameKey_LengthKey (f->string))+3;
            break;

          case pge_opt:
          case pge_mult:
          case pge_sub:
            l += PeepExpression (f->expr);
            break;

          case pge_m2:
            break;


          default:
            break;
        }
      f = f->next;  /* empty  */
    }
  return l;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   PrettyCommentTerm -
*/

static void PrettyCommentTerm (pge_TermDesc t, unsigned int Left)
{
  while (t != NULL)
    {
      CheckNewLine (Left);
      PrettyCommentFactor (t->factor, Left);
      if (t->next != NULL)
        {
          Output_WriteString ((const char *) " | ", 3);
          Indent += 3;
          if (((PeepFactor (t->factor))+Indent) > BaseRightMargin)
            {
              NewLine (Left);
            }
        }
      PrettyFollow ((const char *) "<t:", 3, (const char *) ":t>", 3, t->followinfo);
      t = t->next;
    }
}


/*
   PrettyCommentExpression -
*/

static void PrettyCommentExpression (pge_ExpressionDesc e, unsigned int Left)
{
  if (e != NULL)
    {
      PrettyCommentTerm (e->term, Left);
      PrettyFollow ((const char *) "<e:", 3, (const char *) ":e>", 3, e->followinfo);
    }
}


/*
   PrettyCommentStatement -
*/

static void PrettyCommentStatement (pge_StatementDesc s, unsigned int Left)
{
  if (s != NULL)
    {
      PrettyCommentExpression (s->expr, Left);
      PrettyFollow ((const char *) "<s:", 3, (const char *) ":s>", 3, s->followinfo);
    }
}


/*
   PrettyCommentProduction - generates the comment for rule, p.
*/

static void PrettyCommentProduction (pge_ProductionDesc p)
{
  pge_SetDesc to;

  if (p != NULL)
    {
      BeginningOfLine = TRUE;
      Indent = 0;
      Output_WriteString ((const char *) "(*", 2);
      NewLine (3);
      Output_WriteKey (GetDefinitionName (p));
      Output_WriteString ((const char *) " := ", 4);
      Indent += (NameKey_LengthKey (GetDefinitionName (p)))+4;
      PrettyCommentStatement (p->statement, Indent);
      NewLine (0);
      if (ErrorRecovery)
        {
          NewLine (3);
          Output_WriteString ((const char *) "first  symbols:", 15);
          EmitSet (p->first, static_cast<unsigned int> (0), static_cast<unsigned int> (0));
          NewLine (3);
          PrettyFollow ((const char *) "<p:", 3, (const char *) ":p>", 3, p->followinfo);
          NewLine (3);
          switch (GetReachEnd (p->followinfo))
            {
              case pge_true:
                Output_WriteString ((const char *) "reachend", 8);
                break;

              case pge_false:
                Output_WriteString ((const char *) "cannot reachend", 15);
                break;

              case pge_unknown:
                Output_WriteString ((const char *) "unknown...", 10);
                break;


              default:
                break;
            }
          NewLine (0);
        }
      Output_WriteString ((const char *) "*)", 2);
      NewLine (0);
    }
}


/*
   PrettyPrintProduction - pretty prints the ebnf rule, p.
*/

static void PrettyPrintProduction (pge_ProductionDesc p)
{
  pge_SetDesc to;

  if (p != NULL)
    {
      BeginningOfLine = TRUE;
      Indent = 0;
      if (Texinfo)
        {
          Output_WriteString ((const char *) "@example", 8);
          NewLine (0);
        }
      else if (Sphinx)
        {
          /* avoid dangling else.  */
          Output_WriteString ((const char *) ".. code-block:: ebnf", 20);
          NewLine (0);
        }
      Output_WriteKey (GetDefinitionName (p));
      Output_WriteString ((const char *) " := ", 4);
      Indent += (NameKey_LengthKey (GetDefinitionName (p)))+4;
      PrettyCommentStatement (p->statement, Indent);
      if (p->description != NameKey_NulName)
        {
          Output_WriteKey (p->description);
        }
      NewLine (0);
      WriteIndent ((NameKey_LengthKey (GetDefinitionName (p)))+1);
      Output_WriteString ((const char *) " =: ", 4);
      NewLine (0);
      if (Texinfo)
        {
          Output_WriteString ((const char *) "@findex ", 8);
          Output_WriteKey (GetDefinitionName (p));
          Output_WriteString ((const char *) " (ebnf)", 7);
          NewLine (0);
          Output_WriteString ((const char *) "@end example", 12);
          NewLine (0);
        }
      else if (Sphinx)
        {
          /* avoid dangling else.  */
          Output_WriteString ((const char *) ".. index::", 10);
          NewLine (0);
          Output_WriteString ((const char *) "  pair: ", 8);
          Output_WriteKey (GetDefinitionName (p));
          Output_WriteString ((const char *) "; (ebnf)", 8);
          NewLine (0);
        }
      NewLine (0);
    }
}


/*
   EmitFileLineTag - emits a line and file tag using the C preprocessor syntax.
*/

static void EmitFileLineTag (unsigned int line)
{
  if (! SuppressFileLineTag && (line != LastLineNo))
    {
      LastLineNo = line;
      if (! OnLineStart)
        {
          Output_WriteLn ();
        }
      Output_WriteString ((const char *) "# ", 2);
      Output_WriteCard (line, 0);
      Output_WriteString ((const char *) " \"", 2);
      Output_WriteString ((const char *) &FileName.array[0], MaxFileName);
      Output_Write ('"');
      Output_WriteLn ();
      OnLineStart = TRUE;
    }
}


/*
   EmitRule - generates a comment and code for rule, p.
*/

static void EmitRule (pge_ProductionDesc p)
{
  if (PrettyPrint)
    {
      PrettyPrintProduction (p);
    }
  else
    {
      PrettyCommentProduction (p);
      if (ErrorRecovery)
        {
          RecoverProduction (p);
        }
      else
        {
          CodeProduction (p);
        }
    }
}


/*
   CodeCondition -
*/

static void CodeCondition (pge_m2condition m)
{
  switch (m)
    {
      case pge_m2if:
      case pge_m2none:
        IndentString ((const char *) "IF ", 3);
        break;

      case pge_m2elsif:
        IndentString ((const char *) "ELSIF ", 6);
        break;

      case pge_m2while:
        IndentString ((const char *) "WHILE ", 6);
        break;


      default:
        Debug_Halt ((const char *) "unrecognised m2condition", 24, 2680, (const char *) "m2/gm2-auto/pge.mod", 19);
        break;
    }
}


/*
   CodeThenDo - codes a "THEN" or "DO" depending upon, m.
*/

static void CodeThenDo (pge_m2condition m)
{
  switch (m)
    {
      case pge_m2if:
      case pge_m2none:
      case pge_m2elsif:
        if (LastLineNo == 0)
          {
            Output_WriteLn ();
          }
        IndentString ((const char *) "THEN", 4);
        Output_WriteLn ();
        break;

      case pge_m2while:
        Output_WriteString ((const char *) " DO", 3);
        Output_WriteLn ();
        break;


      default:
        Debug_Halt ((const char *) "unrecognised m2condition", 24, 2705, (const char *) "m2/gm2-auto/pge.mod", 19);
        break;
    }
  OnLineStart = TRUE;
}


/*
   CodeElseEnd - builds an ELSE END statement using string, end.
*/

static void CodeElseEnd (const char *end_, unsigned int _end_high, unsigned int consumed, pge_FactorDesc f, unsigned int inopt)
{
  char end[_end_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (end, end_, _end_high+1);

  Output_WriteLn ();
  OnLineStart = TRUE;
  EmitFileLineTag (f->line);
  if (! inopt)
    {
      IndentString ((const char *) "ELSE", 4);
      StrIO_WriteLn ();
      Indent += 3;
      if (consumed)
        {
          IndentString ((const char *) "", 0);
          Output_WriteKey (ErrorProcArray);
          Output_Write ('(');
          switch (f->type)
            {
              case pge_id:
                Output_Write ('\'');
                Output_WriteKey (f->ident->name);
                Output_WriteString ((const char *) " - expected", 11);
                Output_WriteString ((const char *) "') ;", 4);
                break;

              case pge_lit:
                if ((NameKey_MakeKey ((const char *) "'", 1)) == f->string)
                  {
                    Output_Write ('"');
                    KeyWord (f->string);
                    Output_WriteString ((const char *) " - expected", 11);
                    Output_WriteString ((const char *) "\") ;", 4);
                  }
                else if ((NameKey_MakeKey ((const char *) "\"", 1)) == f->string)
                  {
                    /* avoid dangling else.  */
                    Output_Write ('\'');
                    KeyWord (f->string);
                    Output_WriteString ((const char *) " - expected", 11);
                    Output_WriteString ((const char *) "') ;", 4);
                  }
                else
                  {
                    /* avoid dangling else.  */
                    Output_Write ('"');
                    Output_Write ('\'');
                    KeyWord (f->string);
                    Output_WriteString ((const char *) "' - expected", 12);
                    Output_WriteString ((const char *) "\") ;", 4);
                  }
                break;


              default:
                break;
            }
          Output_WriteLn ();
        }
      IndentString ((const char *) "RETURN( FALSE )", 15);
      Indent -= 3;
      Output_WriteLn ();
    }
  IndentString ((const char *) end, _end_high);
  Output_WriteLn ();
  OnLineStart = TRUE;
}


/*
   CodeEnd - codes a "END" depending upon, m.
*/

static void CodeEnd (pge_m2condition m, pge_TermDesc t, unsigned int consumed, pge_FactorDesc f, unsigned int inopt)
{
  Indent -= 3;
  Output_WriteLn ();
  OnLineStart = TRUE;
  switch (m)
    {
      case pge_m2none:
        if (t == NULL)
          {
            CodeElseEnd ((const char *) "END ;", 5, consumed, f, inopt);
          }
        break;

      case pge_m2if:
        if (t == NULL)
          {
            CodeElseEnd ((const char *) "END ;  (* if *)", 15, consumed, f, inopt);
          }
        break;

      case pge_m2elsif:
        if (t == NULL)
          {
            CodeElseEnd ((const char *) "END ;  (* elsif *)", 18, consumed, f, inopt);
          }
        break;

      case pge_m2while:
        IndentString ((const char *) "END ;  (* while *)", 18);
        break;


      default:
        Debug_Halt ((const char *) "unrecognised m2condition", 24, 2788, (const char *) "m2/gm2-auto/pge.mod", 19);
        break;
    }
  OnLineStart = FALSE;
}


/*
   EmitNonVarCode - writes out, code, providing it is not a variable declaration.
*/

static void EmitNonVarCode (pge_CodeDesc code, unsigned int curpos, unsigned int left)
{
  unsigned int i;
  pge_CodeHunk t;
  unsigned int seentext;

  t = code->code;
  if ((! (FindStr (&t, &i, (const char *) "VAR", 3))) && EmitCode)
    {
      seentext = FALSE;
      curpos = 0;
      EmitFileLineTag (code->line);
      IndentString ((const char *) "", 0);
      WriteCodeHunkListIndent (code->code, code->indent, &curpos, left, &seentext);
      Output_WriteString ((const char *) " ;", 2);
      Output_WriteLn ();
      OnLineStart = TRUE;
    }
}


/*
   ChainOn -
*/

static pge_FactorDesc ChainOn (pge_FactorDesc codeStack, pge_FactorDesc f)
{
  pge_FactorDesc s;

  f->pushed = NULL;
  if (codeStack == NULL)
    {
      return f;
    }
  else
    {
      s = codeStack;
      while (s->pushed != NULL)
        {
          s = s->pushed;
        }
      s->pushed = f;
      return codeStack;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   FlushCode -
*/

static void FlushCode (pge_FactorDesc *codeStack)
{
  if ((*codeStack) != NULL)
    {
      NewLine (Indent);
      Output_WriteString ((const char *) "(* begin flushing code *)", 25);
      OnLineStart = FALSE;
      while ((*codeStack) != NULL)
        {
          NewLine (Indent);
          EmitNonVarCode ((*codeStack)->code, 0, Indent);
          NewLine (Indent);
          (*codeStack) = (*codeStack)->pushed;
          if ((*codeStack) != NULL)
            {
              Output_WriteString ((const char *) " (* again flushing code *)", 26);
              Output_WriteLn ();
              OnLineStart = TRUE;
            }
        }
      NewLine (Indent);
      Output_WriteString ((const char *) "(* end flushing code *)", 23);
      OnLineStart = FALSE;
    }
}


/*
   CodeFactor -
*/

static void CodeFactor (pge_FactorDesc f, pge_TermDesc t, pge_m2condition l, pge_m2condition n, unsigned int inopt, unsigned int inwhile, unsigned int consumed, pge_FactorDesc codeStack)
{
  if (f == NULL)
    {
      /* avoid dangling else.  */
      if (! inwhile && ! inopt)  /* ((l=m2elsif) OR (l=m2if) OR (l=m2none)) AND  */
        {
          Output_WriteLn ();
          IndentString ((const char *) "RETURN( TRUE )", 14);
          OnLineStart = FALSE;
        }
    }
  else
    {
      EmitFileLineTag (f->line);
      switch (f->type)
        {
          case pge_id:
            FlushCode (&codeStack);
            CodeCondition (n);
            Output_WriteKey (f->ident->name);
            Output_WriteString ((const char *) "()", 2);
            CodeThenDo (n);
            Indent += 3;
            CodeFactor (f->next, NULL, n, pge_m2none, inopt, inwhile, TRUE, NULL);
            CodeEnd (n, t, consumed, f, inopt);
            break;

          case pge_lit:
            FlushCode (&codeStack);
            CodeCondition (n);
            Output_WriteKey (SymIsProc);
            Output_Write ('(');
            Output_WriteKey (SymbolKey_GetSymKey (Aliases, f->string));
            Output_Write (')');
            CodeThenDo (n);
            Indent += 3;
            CodeFactor (f->next, NULL, n, pge_m2none, inopt, inwhile, TRUE, NULL);
            CodeEnd (n, t, consumed, f, inopt);
            break;

          case pge_sub:
            FlushCode (&codeStack);
            CodeExpression (f->expr, pge_m2none, inopt, inwhile, consumed, NULL);
            if (f->next != NULL)
              {
                /* 
                    *  the test above makes sure that we don't emit a RETURN( TRUE )
                    *  after a subexpression. Remember sub expressions are not conditional
  */
                CodeFactor (f->next, t, n, pge_m2none, inopt, inwhile, TRUE, NULL);
              }
            break;

          case pge_opt:
            FlushCode (&codeStack);
            CodeExpression (f->expr, pge_m2if, TRUE, inwhile, FALSE, NULL);
            CodeFactor (f->next, t, n, pge_m2none, inopt, inwhile, consumed, NULL);
            break;

          case pge_mult:
            FlushCode (&codeStack);
            CodeExpression (f->expr, pge_m2while, FALSE, TRUE, consumed, NULL);
            CodeFactor (f->next, t, n, pge_m2none, inopt, inwhile, consumed, NULL);
            break;

          case pge_m2:
            codeStack = ChainOn (codeStack, f);
            if (consumed || (f->next == NULL))
              {
                FlushCode (&codeStack);
              }
            CodeFactor (f->next, t, n, pge_m2none, inopt, inwhile, consumed, codeStack);
            break;


          default:
            break;
        }
    }
}


/*
   CodeTerm -
*/

static void CodeTerm (pge_TermDesc t, pge_m2condition m, unsigned int inopt, unsigned int inwhile, unsigned int consumed, pge_FactorDesc codeStack)
{
  pge_m2condition l;

  l = m;
  while (t != NULL)
    {
      EmitFileLineTag (t->line);
      if ((t->factor->type == pge_m2) && (m == pge_m2elsif))
        {
          m = pge_m2if;
          IndentString ((const char *) "ELSE", 4);
          Output_WriteLn ();
          OnLineStart = TRUE;
          Indent += 3;
          CodeFactor (t->factor, t->next, pge_m2none, pge_m2none, inopt, inwhile, consumed, codeStack);
          Indent -= 3;
          IndentString ((const char *) "END ;", 5);
          Output_WriteLn ();
          OnLineStart = TRUE;
        }
      else
        {
          CodeFactor (t->factor, t->next, pge_m2none, m, inopt, inwhile, consumed, codeStack);
        }
      l = m;
      if (t->next != NULL)
        {
          m = pge_m2elsif;
        }
      t = t->next;
    }
}


/*
   CodeExpression -
*/

static void CodeExpression (pge_ExpressionDesc e, pge_m2condition m, unsigned int inopt, unsigned int inwhile, unsigned int consumed, pge_FactorDesc codeStack)
{
  if (e != NULL)
    {
      EmitFileLineTag (e->line);
      CodeTerm (e->term, m, inopt, inwhile, consumed, codeStack);
    }
}


/*
   CodeStatement -
*/

static void CodeStatement (pge_StatementDesc s, pge_m2condition m)
{
  if (s != NULL)
    {
      EmitFileLineTag (s->line);
      CodeExpression (s->expr, m, FALSE, FALSE, FALSE, NULL);
    }
}


/*
   CodeProduction - only encode grammer rules which are not special.
*/

static void CodeProduction (pge_ProductionDesc p)
{
  if ((p != NULL) && (! p->firstsolved || ((p->statement != NULL) && (p->statement->expr != NULL))))
    {
      BeginningOfLine = TRUE;
      Indent = 0;
      Output_WriteLn ();
      EmitFileLineTag (p->line);
      IndentString ((const char *) "PROCEDURE ", 10);
      Output_WriteKey (GetDefinitionName (p));
      Output_WriteString ((const char *) " () : BOOLEAN ;", 15);
      VarProduction (p);
      Output_WriteLn ();
      OnLineStart = TRUE;
      EmitFileLineTag (p->line);
      IndentString ((const char *) "BEGIN", 5);
      StrIO_WriteLn ();
      OnLineStart = FALSE;
      EmitFileLineTag (p->line);
      Indent = 3;
      CodeStatement (p->statement, pge_m2none);
      Output_WriteLn ();
      Indent = 0;
      IndentString ((const char *) "END ", 4);
      NameKey_WriteKey (GetDefinitionName (p));
      Output_WriteString ((const char *) " ;", 2);
      Output_WriteLn ();
      Output_WriteLn ();
      Output_WriteLn ();
    }
}


/*
   RecoverCondition -
*/

static void RecoverCondition (pge_m2condition m)
{
  switch (m)
    {
      case pge_m2if:
        IndentString ((const char *) "IF ", 3);
        break;

      case pge_m2none:
        IndentString ((const char *) "IF ", 3);
        break;

      case pge_m2elsif:
        IndentString ((const char *) "ELSIF ", 6);
        break;

      case pge_m2while:
        IndentString ((const char *) "WHILE ", 6);
        break;


      default:
        Debug_Halt ((const char *) "unrecognised m2condition", 24, 3045, (const char *) "m2/gm2-auto/pge.mod", 19);
        break;
    }
}


/*
   ConditionIndent - returns the number of spaces indentation created via, m.
*/

static unsigned int ConditionIndent (pge_m2condition m)
{
  switch (m)
    {
      case pge_m2if:
        return 3;
        break;

      case pge_m2none:
        return 3;
        break;

      case pge_m2elsif:
        return 6;
        break;

      case pge_m2while:
        return 6;
        break;


      default:
        Debug_Halt ((const char *) "unrecognised m2condition", 24, 3064, (const char *) "m2/gm2-auto/pge.mod", 19);
        break;
    }
  ReturnException ("m2/gm2-auto/pge.mod", 1, 7);
  __builtin_unreachable ();
}


/*
   WriteGetTokenType - writes out the method of determining the token type.
*/

static void WriteGetTokenType (void)
{
  Output_WriteKey (TokenTypeProc);
}


/*
   NumberOfElements - returns the number of elements in set, to, which lie between low..high
*/

static unsigned int NumberOfElements (pge_SetDesc to, unsigned int low, unsigned int high)
{
  unsigned int n;

  n = 0;
  while (to != NULL)
    {
      switch (to->type)
        {
          case pge_tokel:
            if ((high == 0) || (IsBetween (to->string, low, high)))
              {
                n += 1;
              }
            break;

          case pge_litel:
            if ((high == 0) || (IsBetween (SymbolKey_GetSymKey (Aliases, to->string), low, high)))
              {
                n += 1;
              }
            break;

          case pge_idel:
            PushBackInput_WarnError ((const char *) "not expecting ident in first symbol list", 40);
            WasNoError = FALSE;
            break;


          default:
            PushBackInput_WarnError ((const char *) "unknown enuneration element", 27);
            WasNoError = FALSE;
            break;
        }
      to = to->next;
    }
  return n;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   WriteElement - writes the literal name for element, e.
*/

static void WriteElement (unsigned int e)
{
  Output_WriteKey (SymbolKey_GetSymKey (ReverseValues, e));
}


/*
   EmitIsInSet - writes out the equivalent of GetTokenType() IN { toset }
*/

static void EmitIsInSet (pge_SetDesc to, NameKey_Name low, NameKey_Name high)
{
  if ((NumberOfElements (to, low, high)) == 1)
    {
      WriteGetTokenType ();
      Output_Write ('=');
      EmitSet (to, low, high);
    }
  else
    {
      WriteGetTokenType ();
      Output_WriteString ((const char *) " IN SetOfStop", 13);
      if (LargestValue > MaxElementsInSet)
        {
          Output_WriteCard (((unsigned int ) (low)) / MaxElementsInSet, 0);
        }
      Output_WriteString ((const char *) " {", 2);
      EmitSet (to, low, high);
      Output_WriteString ((const char *) "}", 1);
    }
}


/*
   EmitIsInSubSet - writes out a test to see whether GetTokenype() is in { subset }
*/

static void EmitIsInSubSet (pge_SetDesc to, unsigned int low, unsigned int high)
{
  if ((NumberOfElements (to, low, high)) == 1)
    {
      Output_Write ('(');
      EmitIsInSet (to, low, high);
      Output_Write (')');
    }
  else if (low == 0)
    {
      /* avoid dangling else.  */
      /* no need to check whether GetTokenType > low  */
      Output_WriteString ((const char *) "((", 2);
      WriteGetTokenType ();
      Output_Write ('<');
      WriteElement (static_cast<unsigned int> (((int ) (high))+1));
      Output_WriteString ((const char *) ") AND (", 7);
      EmitIsInSet (to, low, high);
      Output_WriteString ((const char *) "))", 2);
    }
  else if (((unsigned int ) (high)) > LargestValue)
    {
      /* avoid dangling else.  */
      /* no need to check whether GetTokenType < high  */
      Output_WriteString ((const char *) "((", 2);
      WriteGetTokenType ();
      Output_WriteString ((const char *) ">=", 2);
      WriteElement (low);
      Output_WriteString ((const char *) ") AND (", 7);
      EmitIsInSet (to, low, high);
      Output_WriteString ((const char *) "))", 2);
    }
  else
    {
      /* avoid dangling else.  */
      Output_WriteString ((const char *) "((", 2);
      WriteGetTokenType ();
      Output_WriteString ((const char *) ">=", 2);
      WriteElement (low);
      Output_WriteString ((const char *) ") AND (", 7);
      WriteGetTokenType ();
      Output_Write ('<');
      WriteElement (static_cast<unsigned int> (((int ) (high))+1));
      Output_WriteString ((const char *) ") AND (", 7);
      EmitIsInSet (to, low, high);
      Output_WriteString ((const char *) "))", 2);
    }
}


/*
   EmitIsInFirst -
*/

static void EmitIsInFirst (pge_SetDesc to, pge_m2condition m)
{
  unsigned int i;
  unsigned int first;

  if ((NumberOfElements (to, static_cast<unsigned int> (0), static_cast<unsigned int> (0))) == 1)
    {
      /* only one element  */
      WriteGetTokenType ();
      Output_Write ('=');
      EmitSet (to, static_cast<unsigned int> (0), static_cast<unsigned int> (0));
    }
  else
    {
      if (LargestValue <= MaxElementsInSet)
        {
          Output_Write ('(');
          WriteGetTokenType ();
          Output_WriteString ((const char *) " IN ", 4);
          EmitSetAsParameters (to);
          Output_WriteString ((const char *) ")", 1);
        }
      else
        {
          i = 0;
          first = TRUE;
          do {
            if (! (IsEmptySet (to, i*MaxElementsInSet, ((i+1)*MaxElementsInSet)-1)))
              {
                if (! first)
                  {
                    Output_WriteString ((const char *) " OR", 3);
                    NewLine (Indent+(ConditionIndent (m)));
                    Indent -= ConditionIndent (m);
                  }
                EmitIsInSubSet (to, i*MaxElementsInSet, ((i+1)*MaxElementsInSet)-1);
                first = FALSE;
              }
            i += 1;
          } while (! ((i*MaxElementsInSet) > LargestValue));
        }
    }
}

static void FlushRecoverCode (pge_FactorDesc *codeStack)
{
  /* 
   FlushCode -
  */
  if ((*codeStack) != NULL)
    {
      while ((*codeStack) != NULL)
        {
          EmitNonVarCode ((*codeStack)->code, 0, Indent);
          (*codeStack) = (*codeStack)->pushed;
        }
    }
}


/*
   RecoverFactor -
*/

static void RecoverFactor (pge_FactorDesc f, pge_m2condition m, pge_FactorDesc codeStack)
{
  pge_SetDesc to;

  if (f == NULL)
    {}  /* empty.  */
  else
    {
      EmitFileLineTag (f->line);
      switch (f->type)
        {
          case pge_id:
            to = NULL;
            CalcFirstFactor (f, NULL, &to);
            if ((to != NULL) && (m != pge_m2none))
              {
                RecoverCondition (m);
                EmitIsInFirst (to, m);
                CodeThenDo (m);
                Indent += 3;
              }
            FlushRecoverCode (&codeStack);
            IndentString ((const char *) "", 0);
            Output_WriteKey (f->ident->name);
            Output_Write ('(');
            EmitStopParametersAndFollow (f, m);
            Output_WriteString ((const char *) ") ;", 3);
            Output_WriteLn ();
            RecoverFactor (f->next, pge_m2none, codeStack);
            if ((to != NULL) && (m != pge_m2none))
              {
                Indent -= 3;
              }
            break;

          case pge_lit:
            if (m == pge_m2none)
              {
                FlushRecoverCode (&codeStack);
                IndentString ((const char *) "Expect(", 7);
                Output_WriteKey (SymbolKey_GetSymKey (Aliases, f->string));
                Output_WriteString ((const char *) ", ", 2);
                EmitStopParametersAndFollow (f, m);
                Output_WriteString ((const char *) ") ;", 3);
                Output_WriteLn ();
                RecoverFactor (f->next, pge_m2none, codeStack);
              }
            else
              {
                RecoverCondition (m);
                WriteGetTokenType ();
                Output_Write ('=');
                Output_WriteKey (SymbolKey_GetSymKey (Aliases, f->string));
                CodeThenDo (m);
                Indent += 3;
                IndentString ((const char *) "Expect(", 7);
                Output_WriteKey (SymbolKey_GetSymKey (Aliases, f->string));
                Output_WriteString ((const char *) ", ", 2);
                EmitStopParametersAndFollow (f, m);
                Output_WriteString ((const char *) ") ;", 3);
                Output_WriteLn ();
                FlushRecoverCode (&codeStack);
                RecoverFactor (f->next, pge_m2none, codeStack);
                Indent -= 3;
              }
            break;

          case pge_sub:
            FlushRecoverCode (&codeStack);
            RecoverExpression (f->expr, pge_m2none, m);
            RecoverFactor (f->next, pge_m2none, codeStack);
            break;

          case pge_opt:
            FlushRecoverCode (&codeStack);
            if (OptExpSeen (f))
              {
                to = NULL;
                CalcFirstExpression (f->expr, NULL, &to);
                RecoverCondition (m);
                EmitIsInFirst (to, m);
                CodeThenDo (m);
                Indent += 3;
                IndentString ((const char *) "(* seen optional [ | ] expression *)", 36);
                Output_WriteLn ();
                stop ();
                RecoverExpression (f->expr, pge_m2none, pge_m2if);
                IndentString ((const char *) "(* end of optional [ | ] expression *)", 38);
                Output_WriteLn ();
                Indent -= 3;
                IndentString ((const char *) "END ;", 5);
                Output_WriteLn ();
              }
            else
              {
                RecoverExpression (f->expr, pge_m2if, m);
              }
            RecoverFactor (f->next, pge_m2none, codeStack);
            break;

          case pge_mult:
            FlushRecoverCode (&codeStack);
            if (((OptExpSeen (f)) || (m == pge_m2if)) || (m == pge_m2elsif))
              {
                /* avoid dangling else.  */
                to = NULL;
                CalcFirstExpression (f->expr, NULL, &to);
                RecoverCondition (m);
                EmitIsInFirst (to, m);
                CodeThenDo (m);
                Indent += 3;
                IndentString ((const char *) "(* seen optional { | } expression *)", 36);
                Output_WriteLn ();
                RecoverCondition (pge_m2while);
                EmitIsInFirst (to, pge_m2while);
                CodeThenDo (pge_m2while);
                Indent += 3;
                RecoverExpression (f->expr, pge_m2none, pge_m2while);
                IndentString ((const char *) "(* end of optional { | } expression *)", 38);
                Output_WriteLn ();
                Indent -= 3;
                IndentString ((const char *) "END ;", 5);
                Output_WriteLn ();
                Indent -= 3;
                if (m == pge_m2none)
                  {
                    IndentString ((const char *) "END ;", 5);
                    Output_WriteLn ();
                    Indent -= 3;
                  }
              }
            else
              {
                RecoverExpression (f->expr, pge_m2while, m);
              }
            RecoverFactor (f->next, pge_m2none, codeStack);
            break;

          case pge_m2:
            codeStack = ChainOn (codeStack, f);
            if (f->next == NULL)
              {
                FlushRecoverCode (&codeStack);
              }
            else
              {
                RecoverFactor (f->next, m, codeStack);  /* was m2none  */
              }
            break;


          default:
            break;
        }
    }
}


/*
   OptExpSeen - returns TRUE if we can see an optional expression in the factor.
                This is not the same as epsilon. Example { '+' } matches epsilon as
                well as { '+' | '-' } but OptExpSeen returns TRUE in the second case
                and FALSE in the first.
*/

static unsigned int OptExpSeen (pge_FactorDesc f)
{
  if (f == NULL)
    {
      return FALSE;
    }
  else
    {
      switch (f->type)
        {
          case pge_id:
          case pge_lit:
            return FALSE;
            break;

          case pge_sub:
            return FALSE;  /* is this correct?  */
            break;

          case pge_opt:
          case pge_mult:
            return ((f->expr != NULL) && (f->expr->term != NULL)) && (f->expr->term->next != NULL);  /* is this correct?  */
            break;

          case pge_m2:
            return TRUE;
            break;


          default:
            break;
        }
    }
  PushBackInput_WarnError ((const char *) "all cases were not handled", 26);
  WasNoError = FALSE;
  ReturnException ("m2/gm2-auto/pge.mod", 1, 7);
  __builtin_unreachable ();
}


/*
   RecoverTerm -
*/

static void RecoverTerm (pge_TermDesc t, pge_m2condition new_, pge_m2condition old)
{
  unsigned int LastWasM2Only;
  unsigned int alternative;
  pge_SetDesc to;

  LastWasM2Only = (t->factor->type == pge_m2) && (t->factor->next == NULL);  /* does the factor only contain inline code?  */
  to = NULL;
  CalcFirstTerm (t, NULL, &to);
  alternative = FALSE;
  if (t->next != NULL)
    {
      new_ = pge_m2if;
    }
  while (t != NULL)
    {
      EmitFileLineTag (t->line);
      LastWasM2Only = (t->factor->type == pge_m2) && (t->factor->next == NULL);
      if ((t->factor->type == pge_m2) && (new_ == pge_m2elsif))
        {
          new_ = pge_m2if;
          IndentString ((const char *) "ELSE", 4);
          Output_WriteLn ();
          Indent += 3;
          RecoverFactor (t->factor, pge_m2none, NULL);
          alternative = FALSE;
        }
      else
        {
          RecoverFactor (t->factor, new_, NULL);
        }
      if (t->next != NULL)
        {
          new_ = pge_m2elsif;
          alternative = TRUE;
        }
      t = t->next;
    }
  if ((new_ == pge_m2if) || (new_ == pge_m2elsif))
    {
      if (alternative && (old != pge_m2while))
        {
          IndentString ((const char *) "ELSE", 4);
          Output_WriteLn ();
          Indent += 3;
          IndentString ((const char *) "", 0);
          Output_WriteKey (ErrorProcArray);
          Output_WriteString ((const char *) "('expecting one of: ", 20);
          EmitSetName (to, static_cast<unsigned int> (0), static_cast<unsigned int> (0));
          Output_WriteString ((const char *) "')", 2);
          Output_WriteLn ();
          Indent -= 3;
        }
      else if (LastWasM2Only)
        {
          /* avoid dangling else.  */
          Indent -= 3;
        }
      IndentString ((const char *) "END ;", 5);
      Output_WriteLn ();
    }
  else if (new_ == pge_m2while)
    {
      /* avoid dangling else.  */
      IndentString ((const char *) "END (* while *) ;", 17);
      Output_WriteLn ();
    }
  else if (LastWasM2Only)
    {
      /* avoid dangling else.  */
      Indent -= 3;
    }
}


/*
   RecoverExpression -
*/

static void RecoverExpression (pge_ExpressionDesc e, pge_m2condition new_, pge_m2condition old)
{
  if (e != NULL)
    {
      EmitFileLineTag (e->line);
      RecoverTerm (e->term, new_, old);
    }
}


/*
   RecoverStatement -
*/

static void RecoverStatement (pge_StatementDesc s, pge_m2condition m)
{
  if (s != NULL)
    {
      EmitFileLineTag (s->line);
      RecoverExpression (s->expr, m, pge_m2none);
    }
}


/*
   EmitFirstFactor - generate a list of all first tokens between the range: low..high.
*/

static void EmitFirstFactor (pge_FactorDesc f, unsigned int low, unsigned int high)
{
}


/*
   EmitUsed -
*/

static void EmitUsed (unsigned int wordno)
{
  if (! ((((1 << (wordno)) & (ParametersUsed)) != 0)))
    {
      Output_WriteString ((const char *) " (* <* unused *> *) ", 20);
    }
}


/*
   EmitStopParameters - generate the stop set.
*/

static void EmitStopParameters (unsigned int FormalParameters)
{
  unsigned int i;

  if (LargestValue <= MaxElementsInSet)
    {
      Output_WriteString ((const char *) "stopset", 7);
      if (FormalParameters)
        {
          Output_WriteString ((const char *) ": SetOfStop", 11);
          EmitUsed (0);
        }
      else
        {
          ParametersUsed |= (1 << (0 ));
        }
    }
  else
    {
      i = 0;
      do {
        Output_WriteString ((const char *) "stopset", 7);
        Output_WriteCard (i, 0);
        if (FormalParameters)
          {
            Output_WriteString ((const char *) ": SetOfStop", 11);
            Output_WriteCard (i, 0);
            EmitUsed (i);
          }
        else
          {
            ParametersUsed |= (1 << (i ));
          }
        i += 1;
        if ((i*MaxElementsInSet) < LargestValue)
          {
            /* avoid gcc warning by using compound statement even if not strictly necessary.  */
            if (FormalParameters)
              {
                Output_WriteString ((const char *) "; ", 2);
              }
            else
              {
                Output_WriteString ((const char *) ", ", 2);
              }
          }
      } while (! ((i*MaxElementsInSet) >= LargestValue));
    }
}


/*
   IsBetween - returns TRUE if the value of the token, string, is
               in the range: low..high
*/

static unsigned int IsBetween (NameKey_Name string, unsigned int low, unsigned int high)
{
  return ((SymbolKey_GetSymKey (Values, string)) >= low) && ((SymbolKey_GetSymKey (Values, string)) <= high);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   IsEmptySet - returns TRUE if no elements exist in set, to, with values, low..high.
*/

static unsigned int IsEmptySet (pge_SetDesc to, unsigned int low, unsigned int high)
{
  while (to != NULL)
    {
      switch (to->type)
        {
          case pge_tokel:
            if (IsBetween (to->string, low, high))
              {
                return FALSE;
              }
            break;

          case pge_litel:
            if (IsBetween (SymbolKey_GetSymKey (Aliases, to->string), low, high))
              {
                return FALSE;
              }
            break;

          case pge_idel:
            PushBackInput_WarnError ((const char *) "not expecting ident in first symbol list", 40);
            WasNoError = FALSE;
            break;


          default:
            PushBackInput_WarnError ((const char *) "unknown enuneration element", 27);
            WasNoError = FALSE;
            break;
        }
      to = to->next;
    }
  return TRUE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   EmitSet - emits the tokens in the set, to, which have values low..high
*/

static void EmitSet (pge_SetDesc to, unsigned int low, unsigned int high)
{
  unsigned int first;

  first = TRUE;
  while (to != NULL)
    {
      switch (to->type)
        {
          case pge_tokel:
            if ((high == 0) || (IsBetween (to->string, low, high)))
              {
                if (! first)
                  {
                    Output_WriteString ((const char *) ", ", 2);
                  }
                Output_WriteKey (to->string);
                first = FALSE;
              }
            break;

          case pge_litel:
            if ((high == 0) || (IsBetween (SymbolKey_GetSymKey (Aliases, to->string), low, high)))
              {
                if (! first)
                  {
                    Output_WriteString ((const char *) ", ", 2);
                  }
                Output_WriteKey (SymbolKey_GetSymKey (Aliases, to->string));
                first = FALSE;
              }
            break;

          case pge_idel:
            PushBackInput_WarnError ((const char *) "not expecting ident in first symbol list", 40);
            WasNoError = FALSE;
            break;


          default:
            PushBackInput_WarnError ((const char *) "unknown enuneration element", 27);
            WasNoError = FALSE;
            break;
        }
      to = to->next;
    }
}


/*
   EmitSetName - emits the tokens in the set, to, which have values low..high, using
                 their names.
*/

static void EmitSetName (pge_SetDesc to, unsigned int low, unsigned int high)
{
  while (to != NULL)
    {
      switch (to->type)
        {
          case pge_tokel:
            if ((high == 0) || (IsBetween (to->string, low, high)))
              {
                /* avoid gcc warning by using compound statement even if not strictly necessary.  */
                if ((NameKey_MakeKey ((const char *) "'", 1)) == (SymbolKey_GetSymKey (ReverseAliases, to->string)))
                  {
                    Output_WriteString ((const char *) "single quote", 12);
                  }
                else
                  {
                    KeyWord (SymbolKey_GetSymKey (ReverseAliases, to->string));
                  }
              }
            break;

          case pge_litel:
            if ((high == 0) || (IsBetween (SymbolKey_GetSymKey (Aliases, to->string), low, high)))
              {
                Output_WriteKey (to->string);
              }
            break;

          case pge_idel:
            PushBackInput_WarnError ((const char *) "not expecting ident in first symbol list", 40);
            WasNoError = FALSE;
            break;


          default:
            PushBackInput_WarnError ((const char *) "unknown enuneration element", 27);
            WasNoError = FALSE;
            break;
        }
      to = to->next;
      if (to != NULL)
        {
          Output_Write (' ');
        }
    }
}


/*
   EmitStopParametersAndSet - generates the stop parameters together with a set
                              inclusion of all the symbols in set, to.
*/

static void EmitStopParametersAndSet (pge_SetDesc to)
{
  unsigned int i;

  if (LargestValue <= MaxElementsInSet)
    {
      /* avoid dangling else.  */
      Output_WriteString ((const char *) "stopset", 7);
      ParametersUsed |= (1 << (0 ));
      if ((to != NULL) && ((NumberOfElements (to, static_cast<unsigned int> (0), static_cast<unsigned int> (MaxElementsInSet-1))) > 0))
        {
          Output_WriteString ((const char *) " + SetOfStop", 12);
          Output_Write ('{');
          EmitSet (to, static_cast<unsigned int> (0), static_cast<unsigned int> (MaxElementsInSet-1));
          Output_Write ('}');
        }
    }
  else
    {
      i = 0;
      do {
        Output_WriteString ((const char *) "stopset", 7);
        Output_WriteCard (i, 0);
        ParametersUsed |= (1 << (i ));
        if ((to != NULL) && ((NumberOfElements (to, i*MaxElementsInSet, ((i+1)*MaxElementsInSet)-1)) > 0))
          {
            Output_WriteString ((const char *) " + SetOfStop", 12);
            Output_WriteCard (i, 0);
            Output_Write ('{');
            EmitSet (to, i*MaxElementsInSet, ((i+1)*MaxElementsInSet)-1);
            Output_Write ('}');
          }
        i += 1;
        if ((i*MaxElementsInSet) < LargestValue)
          {
            Output_WriteString ((const char *) ", ", 2);
          }
      } while (! ((i*MaxElementsInSet) >= LargestValue));
    }
}


/*
   EmitSetAsParameters - generates the first symbols as parameters to a set function.
*/

static void EmitSetAsParameters (pge_SetDesc to)
{
  unsigned int i;

  if (LargestValue <= MaxElementsInSet)
    {
      Output_Write ('{');
      EmitSet (to, static_cast<unsigned int> (0), static_cast<unsigned int> (MaxElementsInSet-1));
    }
  else
    {
      i = 0;
      do {
        Output_Write ('{');
        EmitSet (to, i*MaxElementsInSet, ((i+1)*MaxElementsInSet)-1);
        i += 1;
        if (((i+1)*MaxElementsInSet) > LargestValue)
          {
            Output_WriteString ((const char *) "}, ", 3);
          }
      } while (! (((i+1)*MaxElementsInSet) >= LargestValue));
    }
  Output_Write ('}');
}


/*
   EmitStopParametersAndFollow - generates the stop parameters together with a set
                                 inclusion of all the follow symbols for subsequent
                                 sentances.
*/

static void EmitStopParametersAndFollow (pge_FactorDesc f, pge_m2condition m)
{
  pge_SetDesc to;

  to = NULL;
  /* 
   IF m=m2while
   THEN
      CalcFirstFactor(f, NIL, to)
   END ;
  */
  CollectFollow (&to, f->followinfo);
  EmitStopParametersAndSet (to);
  if (Debugging)
    {
      Output_WriteLn ();
      Output_WriteString ((const char *) "factor is: ", 11);
      PrettyCommentFactor (f, StrLib_StrLen ((const char *) "factor is: ", 11));
      Output_WriteLn ();
      Output_WriteString ((const char *) "follow set:", 11);
      EmitSet (to, static_cast<unsigned int> (0), static_cast<unsigned int> (0));
      Output_WriteLn ();
    }
}


/*
   EmitFirstAsParameters -
*/

static void EmitFirstAsParameters (pge_FactorDesc f)
{
  pge_SetDesc to;

  to = NULL;
  CalcFirstFactor (f, NULL, &to);
  EmitSetAsParameters (to);
}


/*
   RecoverProduction - only encode grammer rules which are not special.
                       Generate error recovery code.
*/

static void RecoverProduction (pge_ProductionDesc p)
{
  DynamicStrings_String s;

  if ((p != NULL) && (! p->firstsolved || ((p->statement != NULL) && (p->statement->expr != NULL))))
    {
      BeginningOfLine = TRUE;
      Indent = 0;
      Output_WriteLn ();
      OnLineStart = FALSE;
      EmitFileLineTag (p->line);
      IndentString ((const char *) "PROCEDURE ", 10);
      Output_WriteKey (GetDefinitionName (p));
      Output_WriteString ((const char *) " (", 2);
      ParametersUsed = (unsigned int) 0;
      Output_StartBuffer ();
      Output_WriteString ((const char *) ") ;", 3);
      VarProduction (p);
      Output_WriteLn ();
      OnLineStart = FALSE;
      EmitFileLineTag (p->line);
      Indent = 0;
      IndentString ((const char *) "BEGIN", 5);
      Output_WriteLn ();
      OnLineStart = FALSE;
      EmitFileLineTag (p->line);
      Indent = 3;
      RecoverStatement (p->statement, pge_m2none);
      Indent = 0;
      IndentString ((const char *) "END ", 4);
      Output_WriteKey (GetDefinitionName (p));
      Output_WriteString ((const char *) " ;", 2);
      Output_WriteLn ();
      Output_WriteLn ();
      Output_WriteLn ();
      s = Output_EndBuffer ();
      EmitStopParameters (TRUE);
      Output_KillWriteS (s);
    }
}


/*
   IsWhite - returns TRUE if, ch, is a space or a tab.
*/

static unsigned int IsWhite (char ch)
{
  return ((ch == ' ') || (ch == ASCII_tab)) || (ch == ASCII_lf);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   FindStr - returns TRUE if, str, was seen inside the code hunk
*/

static unsigned int FindStr (pge_CodeHunk *code, unsigned int *i, const char *str_, unsigned int _str_high)
{
  unsigned int j;
  unsigned int k;
  pge_CodeHunk t;
  char str[_str_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (str, str_, _str_high+1);

  t = (*code);
  k = (StrLib_StrLen ((const char *) &(*code)->codetext.array[0], MaxCodeHunkLength))+1;
  while (t != NULL)
    {
      do {
        while ((k > 0) && (IsWhite (t->codetext.array[k-1])))
          {
            k -= 1;
          }
        if (k == 0)
          {
            t = t->next;
            k = MaxCodeHunkLength+1;
          }
      } while (! ((t == NULL) || (! (IsWhite (t->codetext.array[k-1])))));
      /* found another word check it  */
      if (t != NULL)
        {
          j = StrLib_StrLen ((const char *) str, _str_high);
          (*i) = k;
          while (((t != NULL) && (j > 0)) && ((str[j-1] == t->codetext.array[k-1]) || ((IsWhite (str[j-1])) && (IsWhite (t->codetext.array[k-1])))))
            {
              j -= 1;
              k -= 1;
              if (j == 0)
                {
                  /* found word remember position  */
                  (*code) = t;
                }
              if (k == 0)
                {
                  t = t->next;
                  k = MaxCodeHunkLength+1;
                }
            }
          if (k > 0)
            {
              k -= 1;
            }
          else
            {
              t = t->next;
            }
        }
    }
  return (t == NULL) && (j == 0);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   WriteUpto -
*/

static void WriteUpto (pge_CodeHunk code, pge_CodeHunk upto, unsigned int limit)
{
  if (code != upto)
    {
      WriteUpto (code->next, upto, limit);
      Output_WriteString ((const char *) &code->codetext.array[0], MaxCodeHunkLength);
    }
  else
    {
      while ((limit <= MaxCodeHunkLength) && (code->codetext.array[limit] != ASCII_nul))
        {
          Output_Write (code->codetext.array[limit]);
          limit += 1;
        }
    }
}


/*
   CheckForVar - checks for any local variables which need to be emitted during
                 this production.
*/

static void CheckForVar (pge_CodeHunk code)
{
  unsigned int i;
  pge_CodeHunk t;

  t = code;
  if ((FindStr (&t, &i, (const char *) "VAR", 3)) && EmitCode)
    {
      if (! EmittedVar)
        {
          Output_WriteLn ();
          Indent = 0;
          IndentString ((const char *) "VAR", 3);
          Indent += 3;
          Output_WriteLn ();
          EmittedVar = TRUE;
        }
      WriteUpto (code, t, i);
    }
}


/*
   VarFactor -
*/

static void VarFactor (pge_FactorDesc f)
{
  while (f != NULL)
    {
      switch (f->type)
        {
          case pge_id:
            break;

          case pge_lit:
            break;

          case pge_sub:
          case pge_opt:
          case pge_mult:
            VarExpression (f->expr);
            break;

          case pge_m2:
            CheckForVar (f->code->code);
            break;


          default:
            break;
        }
      f = f->next;
    }
}


/*
   VarTerm -
*/

static void VarTerm (pge_TermDesc t)
{
  while (t != NULL)
    {
      VarFactor (t->factor);
      t = t->next;
    }
}


/*
   VarExpression -
*/

static void VarExpression (pge_ExpressionDesc e)
{
  if (e != NULL)
    {
      VarTerm (e->term);
    }
}


/*
   VarStatement -
*/

static void VarStatement (pge_StatementDesc s)
{
  if (s != NULL)
    {
      VarExpression (s->expr);
    }
}


/*
   VarProduction - writes out all variable declarations.
*/

static void VarProduction (pge_ProductionDesc p)
{
  EmittedVar = FALSE;
  if (p != NULL)
    {
      VarStatement (p->statement);
    }
}


/*
   In - returns TRUE if token, s, is already in the set, to.
*/

static unsigned int In (pge_SetDesc to, NameKey_Name s)
{
  while (to != NULL)
    {
      switch (to->type)
        {
          case pge_idel:
            if (s == to->ident->name)
              {
                return TRUE;
              }
            break;

          case pge_tokel:
          case pge_litel:
            if (s == to->string)
              {
                return TRUE;
              }
            break;


          default:
            PushBackInput_WarnError ((const char *) "internal error CASE type not known", 34);
            WasNoError = FALSE;
            break;
        }
      to = to->next;
    }
  return FALSE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   IntersectionIsNil - given two set lists, s1, s2, return TRUE if the
                       s1 * s2 = {}
*/

static unsigned int IntersectionIsNil (pge_SetDesc s1, pge_SetDesc s2)
{
  while (s1 != NULL)
    {
      switch (s1->type)
        {
          case pge_idel:
            if (In (s2, s1->ident->name))
              {
                return FALSE;
              }
            break;

          case pge_tokel:
          case pge_litel:
            if (In (s2, s1->string))
              {
                return FALSE;
              }
            break;


          default:
            PushBackInput_WarnError ((const char *) "internal error CASE type not known", 34);
            WasNoError = FALSE;
            break;
        }
      s1 = s1->next;
    }
  return TRUE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   AddSet - adds a first symbol to a production.
*/

static void AddSet (pge_SetDesc *to, NameKey_Name s)
{
  pge_SetDesc d;

  if (! (In ((*to), s)))
    {
      d = NewSetDesc ();
      d->type = pge_tokel;
      d->string = s;
      d->next = (*to);
      (*to) = d;
      Finished = FALSE;
    }
}


/*
   OrSet -
*/

static void OrSet (pge_SetDesc *to, pge_SetDesc from)
{
  while (from != NULL)
    {
      switch (from->type)
        {
          case pge_tokel:
            AddSet (to, from->string);
            break;

          case pge_litel:
            AddSet (to, SymbolKey_GetSymKey (Aliases, from->string));
            break;

          case pge_idel:
            PushBackInput_WarnError ((const char *) "not expecting ident in first symbol list", 40);
            WasNoError = FALSE;
            break;


          default:
            Debug_Halt ((const char *) "unknown element in enumeration type", 35, 4122, (const char *) "m2/gm2-auto/pge.mod", 19);
            break;
        }
      from = from->next;
    }
}


/*
   CalcFirstFactor -
*/

static void CalcFirstFactor (pge_FactorDesc f, pge_ProductionDesc from, pge_SetDesc *to)
{
  while (f != NULL)
    {
      switch (f->type)
        {
          case pge_id:
            if (f->ident->definition == NULL)
              {
                WarnError1 ((const char *) "no rule found for an 'ident' called '%s'", 40, f->ident->name);
                M2RTS_HALT (-1);
                __builtin_unreachable ();
              }
            OrSet (to, f->ident->definition->first);
            if ((GetReachEnd (f->ident->definition->followinfo)) == pge_false)
              {
                return ;
              }
            break;

          case pge_lit:
            if ((SymbolKey_GetSymKey (Aliases, f->string)) == SymbolKey_NulKey)
              {
                WarnError1 ((const char *) "unknown token for '%s'", 22, f->string);
                WasNoError = FALSE;
              }
            else
              {
                AddSet (to, SymbolKey_GetSymKey (Aliases, f->string));
              }
            return ;
            break;

          case pge_sub:
          case pge_opt:
          case pge_mult:
            CalcFirstExpression (f->expr, from, to);
            break;

          case pge_m2:
            break;


          default:
            break;
        }
      f = f->next;
    }
}


/*
   CalcFirstTerm -
*/

static void CalcFirstTerm (pge_TermDesc t, pge_ProductionDesc from, pge_SetDesc *to)
{
  while (t != NULL)
    {
      CalcFirstFactor (t->factor, from, to);
      t = t->next;
    }
}


/*
   CalcFirstExpression -
*/

static void CalcFirstExpression (pge_ExpressionDesc e, pge_ProductionDesc from, pge_SetDesc *to)
{
  if (e != NULL)
    {
      CalcFirstTerm (e->term, from, to);
    }
}


/*
   CalcFirstStatement -
*/

static void CalcFirstStatement (pge_StatementDesc s, pge_ProductionDesc from, pge_SetDesc *to)
{
  if (s != NULL)
    {
      CalcFirstExpression (s->expr, from, to);
    }
}


/*
   CalcFirstProduction - calculates all of the first symbols for the grammer
*/

static void CalcFirstProduction (pge_ProductionDesc p, pge_ProductionDesc from, pge_SetDesc *to)
{
  pge_SetDesc s;

  if (p != NULL)
    {
      /* avoid gcc warning by using compound statement even if not strictly necessary.  */
      if (p->firstsolved)
        {
          s = p->first;
          while (s != NULL)
            {
              switch (s->type)
                {
                  case pge_idel:
                    CalcFirstProduction (s->ident->definition, from, to);
                    break;

                  case pge_tokel:
                  case pge_litel:
                    AddSet (to, s->string);
                    break;


                  default:
                    break;
                }
              s = s->next;
            }
        }
      else
        {
          CalcFirstStatement (p->statement, from, to);
        }
    }
}

static void WorkOutFollowFactor (pge_FactorDesc f, pge_SetDesc *followset, pge_SetDesc after)
{
  pge_TraverseResult foundepsilon;
  pge_TraverseResult canreachend;

  /* 
   WorkOutFollow -
  */
  foundepsilon = pge_true;
  canreachend = pge_true;
  while ((f != NULL) && (foundepsilon == pge_true))
    {
      switch (f->type)
        {
          case pge_id:
            if (f->ident->definition == NULL)
              {
                WarnError1 ((const char *) "no rule found for an 'ident' called '%s'", 40, f->ident->name);
                M2RTS_HALT (-1);
                __builtin_unreachable ();
              }
            OrSet (followset, f->ident->definition->first);
            break;

          case pge_lit:
            AddSet (followset, SymbolKey_GetSymKey (Aliases, f->string));
            break;

          case pge_sub:
            WorkOutFollowExpression (f->expr, followset, NULL);
            break;

          case pge_opt:
            WorkOutFollowExpression (f->expr, followset, NULL);
            break;

          case pge_mult:
            WorkOutFollowExpression (f->expr, followset, NULL);
            break;

          case pge_m2:
            break;


          default:
            break;
        }
      if ((GetEpsilon (f->followinfo)) == pge_unknown)
        {
          PushBackInput_WarnError ((const char *) "internal error: epsilon unknown", 31);
          PrettyCommentFactor (f, 3);
          WasNoError = FALSE;
        }
      foundepsilon = GetEpsilon (f->followinfo);
      canreachend = GetReachEnd (f->followinfo);  /* only goes from FALSE -> TRUE  */
      f = f->next;  /* only goes from FALSE -> TRUE  */
    }
  if (canreachend == pge_true)
    {
      OrSet (followset, after);
    }
}


/*
   WorkOutFollowTerm -
*/

static void WorkOutFollowTerm (pge_TermDesc t, pge_SetDesc *followset, pge_SetDesc after)
{
  if (t != NULL)
    {
      while (t != NULL)
        {
          WorkOutFollowFactor (t->factor, followset, after);  /* { '|' Term }  */
          t = t->next;  /* { '|' Term }  */
        }
    }
}


/*
   WorkOutFollowExpression -
*/

static void WorkOutFollowExpression (pge_ExpressionDesc e, pge_SetDesc *followset, pge_SetDesc after)
{
  if (e != NULL)
    {
      WorkOutFollowTerm (e->term, followset, after);
    }
}


/*
   CollectFollow - collects the follow set from, f, into, to.
*/

static void CollectFollow (pge_SetDesc *to, pge_FollowDesc f)
{
  OrSet (to, f->follow);
}


/*
   CalcFollowFactor -
*/

static void CalcFollowFactor (pge_FactorDesc f, pge_SetDesc after)
{
  while (f != NULL)
    {
      switch (f->type)
        {
          case pge_id:
            WorkOutFollowFactor (f->next, &f->followinfo->follow, after);
            break;

          case pge_lit:
            WorkOutFollowFactor (f->next, &f->followinfo->follow, after);
            break;

          case pge_opt:
          case pge_sub:
            CalcFirstFactor (f->next, NULL, &f->followinfo->follow);
            if ((f->next == NULL) || ((GetReachEnd (f->next->followinfo)) == pge_true))
              {
                OrSet (&f->followinfo->follow, after);
                CalcFollowExpression (f->expr, f->followinfo->follow);
              }
            else
              {
                CalcFollowExpression (f->expr, f->followinfo->follow);
              }
            break;

          case pge_mult:
            CalcFirstFactor (f, NULL, &f->followinfo->follow);
            /* include first as we may repeat this sentance  */
            if (Debugging)
              {
                StrIO_WriteLn ();
                StrIO_WriteString ((const char *) "found mult: and first is: ", 26);
                EmitSet (f->followinfo->follow, static_cast<unsigned int> (0), static_cast<unsigned int> (0));
                StrIO_WriteLn ();
              }
            if ((f->next == NULL) || ((GetReachEnd (f->next->followinfo)) == pge_true))
              {
                OrSet (&f->followinfo->follow, after);
                CalcFollowExpression (f->expr, f->followinfo->follow);
              }
            else
              {
                CalcFollowExpression (f->expr, f->followinfo->follow);
              }
            break;


          default:
            break;
        }
      f = f->next;
    }
}


/*
   CalcFollowTerm -
*/

static void CalcFollowTerm (pge_TermDesc t, pge_SetDesc after)
{
  if (t != NULL)
    {
      while (t != NULL)
        {
          CalcFollowFactor (t->factor, after);  /* { '|' Term }  */
          t = t->next;  /* { '|' Term }  */
        }
    }
}


/*
   CalcFollowExpression -
*/

static void CalcFollowExpression (pge_ExpressionDesc e, pge_SetDesc after)
{
  if (e != NULL)
    {
      CalcFollowTerm (e->term, after);
    }
}


/*
   CalcFollowStatement - given a bnf statement generate the follow set.
*/

static void CalcFollowStatement (pge_StatementDesc s)
{
  if (s != NULL)
    {
      CalcFollowExpression (s->expr, NULL);
    }
}


/*
   CalcFollowProduction -
*/

static void CalcFollowProduction (pge_ProductionDesc p)
{
  if (p != NULL)
    {
      CalcFollowStatement (p->statement);
    }
}


/*
   CalcEpsilonFactor -
*/

static void CalcEpsilonFactor (pge_FactorDesc f)
{
  while (f != NULL)
    {
      switch (f->type)
        {
          case pge_id:
            AssignEpsilon ((GetEpsilon (f->ident->definition->followinfo)) != pge_unknown, f->followinfo, GetEpsilon (f->ident->definition->followinfo));
            break;

          case pge_lit:
            AssignEpsilon (TRUE, f->followinfo, pge_false);
            break;

          case pge_sub:
            CalcEpsilonExpression (f->expr);
            AssignEpsilon ((GetEpsilon (f->expr->followinfo)) != pge_unknown, f->followinfo, GetEpsilon (f->expr->followinfo));
            break;

          case pge_m2:
            AssignEpsilon (TRUE, f->followinfo, pge_true);
            break;

          case pge_opt:
          case pge_mult:
            CalcEpsilonExpression (f->expr);
            AssignEpsilon (TRUE, f->followinfo, pge_true);
            break;


          default:
            break;
        }
      f = f->next;
    }
}


/*
   CalcEpsilonTerm -
*/

static void CalcEpsilonTerm (pge_TermDesc t)
{
  if (t != NULL)
    {
      while (t != NULL)
        {
          if (t->factor != NULL)
            {
              switch (GetReachEnd (t->factor->followinfo))
                {
                  case pge_true:
                    AssignEpsilon (TRUE, t->followinfo, pge_true);
                    break;

                  case pge_false:
                    AssignEpsilon (TRUE, t->followinfo, pge_false);
                    break;

                  case pge_unknown:
                    break;


                  default:
                    break;
                }
            }
          CalcEpsilonFactor (t->factor);  /* { '|' Term }  */
          t = t->next;
        }
    }
}


/*
   CalcEpsilonExpression -
*/

static void CalcEpsilonExpression (pge_ExpressionDesc e)
{
  pge_TermDesc t;
  pge_TraverseResult result;

  if (e != NULL)
    {
      CalcEpsilonTerm (e->term);
      if ((GetEpsilon (e->followinfo)) == pge_unknown)
        {
          result = pge_unknown;
          t = e->term;
          while (t != NULL)
            {
              if ((GetEpsilon (t->followinfo)) != pge_unknown)
                {
                  stop ();
                }
              switch (GetEpsilon (t->followinfo))
                {
                  case pge_unknown:
                    break;

                  case pge_true:
                    result = pge_true;
                    break;

                  case pge_false:
                    if (result != pge_true)
                      {
                        result = pge_false;
                      }
                    break;


                  default:
                    break;
                }
              t = t->next;
            }
          AssignEpsilon (result != pge_unknown, e->followinfo, result);
        }
    }
}


/*
   CalcEpsilonStatement - given a bnf statement generate the follow set.
*/

static void CalcEpsilonStatement (pge_StatementDesc s)
{
  if (s != NULL)
    {
      if (s->expr != NULL)
        {
          AssignEpsilon ((GetEpsilon (s->expr->followinfo)) != pge_unknown, s->followinfo, GetEpsilon (s->expr->followinfo));
        }
      CalcEpsilonExpression (s->expr);
    }
}


/*
   CalcEpsilonProduction -
*/

static void CalcEpsilonProduction (pge_ProductionDesc p)
{
  if (p != NULL)
    {
      /* 
      IF p^.statement^.ident^.name=MakeKey('DefinitionModule')
      THEN
         stop
      END ;
  */
      if (Debugging)
        {
          NameKey_WriteKey (p->statement->ident->name);
          StrIO_WriteString ((const char *) "  calculating epsilon", 21);
          StrIO_WriteLn ();
        }
      AssignEpsilon ((GetEpsilon (p->statement->followinfo)) != pge_unknown, p->followinfo, GetEpsilon (p->statement->followinfo));
      CalcEpsilonStatement (p->statement);
    }
}


/*
   CalcReachEndFactor -
*/

static pge_TraverseResult CalcReachEndFactor (pge_FactorDesc f)
{
  pge_TraverseResult canreachend;
  pge_TraverseResult result;

  if (f == NULL)
    {
      return pge_true;  /* we have reached the end of this factor list  */
    }
  else
    {
      /* we need to traverse all factors even if we can short cut the answer to this list of factors  */
      result = CalcReachEndFactor (f->next);
      switch (f->type)
        {
          case pge_id:
            if (f->ident->definition == NULL)
              {
                WarnError1 ((const char *) "definition for %s is absent (assuming epsilon is false for this production)", 75, f->ident->name);
                result = pge_false;
              }
            else if (result != pge_false)
              {
                /* avoid dangling else.  */
                switch (GetReachEnd (f->ident->definition->followinfo))
                  {
                    case pge_false:
                      result = pge_false;
                      break;

                    case pge_true:
                      break;

                    case pge_unknown:
                      result = pge_unknown;
                      break;


                    default:
                      break;
                  }
              }
            break;

          case pge_lit:
            result = pge_false;
            break;

          case pge_sub:
            CalcReachEndExpression (f->expr);
            if ((f->expr != NULL) && (result == pge_true))
              {
                result = GetReachEnd (f->expr->followinfo);
              }
            break;

          case pge_mult:
          case pge_opt:
            if (f->expr != NULL)
              {
                /* not interested in the result as expression is optional  */
                CalcReachEndExpression (f->expr);
              }
            break;

          case pge_m2:
            break;


          default:
            break;
        }
      AssignReachEnd (result != pge_unknown, f->followinfo, result);
      return result;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   CalcReachEndTerm -
*/

static pge_TraverseResult CalcReachEndTerm (pge_TermDesc t)
{
  pge_TraverseResult canreachend;
  pge_TraverseResult result;

  if (t != NULL)
    {
      canreachend = pge_false;
      while (t != NULL)
        {
          result = CalcReachEndFactor (t->factor);
          AssignReachEnd (result != pge_unknown, t->followinfo, result);
          switch (result)
            {
              case pge_true:
                canreachend = pge_true;
                break;

              case pge_false:
                break;

              case pge_unknown:
                if (canreachend == pge_false)
                  {
                    canreachend = pge_unknown;
                  }
                break;


              default:
                break;
            }
          t = t->next;  /* { '|' Term }  */
        }
      return canreachend;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   CalcReachEndExpression -
*/

static void CalcReachEndExpression (pge_ExpressionDesc e)
{
  pge_TraverseResult result;

  if (e == NULL)
    {}  /* empty.  */
  else
    {
      /* no expression, thus reached the end of this sentance  */
      result = CalcReachEndTerm (e->term);
      AssignReachEnd (result != pge_unknown, e->followinfo, result);
    }
}


/*
   CalcReachEndStatement -
*/

static void CalcReachEndStatement (pge_StatementDesc s)
{
  if (s != NULL)
    {
      if (s->expr != NULL)
        {
          CalcReachEndExpression (s->expr);
          AssignReachEnd ((GetReachEnd (s->expr->followinfo)) != pge_unknown, s->followinfo, GetReachEnd (s->expr->followinfo));
        }
    }
}


/*
   CalcReachEndStatement -
*/

static void stop (void)
{
}


/*
   CalcReachEndProduction -
*/

static void CalcReachEndProduction (pge_ProductionDesc p)
{
  if (p != NULL)
    {
      CalcReachEndStatement (p->statement);
      if ((GetReachEnd (p->followinfo)) != pge_unknown)
        {
          if (Debugging)
            {
              StrIO_WriteString ((const char *) "already calculated reach end for: ", 34);
              NameKey_WriteKey (p->statement->ident->name);
              StrIO_WriteString ((const char *) " its value is ", 14);
              if ((GetReachEnd (p->followinfo)) == pge_true)
                {
                  StrIO_WriteString ((const char *) "reachable", 9);
                }
              else
                {
                  StrIO_WriteString ((const char *) "non reachable", 13);
                }
              StrIO_WriteLn ();
            }
        }
      AssignReachEnd ((GetReachEnd (p->statement->followinfo)) != pge_unknown, p->followinfo, GetReachEnd (p->statement->followinfo));
    }
}


/*
   EmptyFactor -
*/

static unsigned int EmptyFactor (pge_FactorDesc f)
{
  while (f != NULL)
    {
      switch (f->type)
        {
          case pge_id:
            if (! (EmptyProduction (f->ident->definition)))
              {
                return FALSE;
              }
            break;

          case pge_lit:
            return FALSE;
            break;

          case pge_sub:
            if (! (EmptyExpression (f->expr)))
              {
                return FALSE;
              }
            break;

          case pge_opt:
          case pge_mult:
            return TRUE;
            break;

          case pge_m2:
            break;


          default:
            break;
        }
      f = f->next;
    }
  return TRUE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   EmptyTerm - returns TRUE if the term maybe empty.
*/

static unsigned int EmptyTerm (pge_TermDesc t)
{
  while (t != NULL)
    {
      if (EmptyFactor (t->factor))
        {
          return TRUE;
        }
      else
        {
          t = t->next;
        }
    }
  return FALSE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   EmptyExpression -
*/

static unsigned int EmptyExpression (pge_ExpressionDesc e)
{
  if (e == NULL)
    {
      return TRUE;
    }
  else
    {
      return EmptyTerm (e->term);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   EmptyStatement - returns TRUE if statement, s, is empty.
*/

static unsigned int EmptyStatement (pge_StatementDesc s)
{
  if (s == NULL)
    {
      return TRUE;
    }
  else
    {
      return EmptyExpression (s->expr);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   EmptyProduction - returns if production, p, maybe empty.
*/

static unsigned int EmptyProduction (pge_ProductionDesc p)
{
  if (p == NULL)
    {
      PushBackInput_WarnError ((const char *) "unknown production", 18);
      return TRUE;
    }
  else if (p->firstsolved && (p->first != NULL))
    {
      /* avoid dangling else.  */
      /* predefined but first set to something - thus not empty  */
      return FALSE;
    }
  else
    {
      /* avoid dangling else.  */
      return EmptyStatement (p->statement);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   EmitFDLNotice -
*/

static void EmitFDLNotice (void)
{
  Output_WriteString ((const char *) "@c Copyright (C) 2000-2023 Free Software Foundation, Inc.", 57);
  Output_WriteLn ();
  Output_WriteLn ();
  Output_WriteString ((const char *) "@c This file is part of GCC.", 28);
  Output_WriteLn ();
  Output_WriteString ((const char *) "@c Permission is granted to copy, distribute and/or modify this document", 72);
  Output_WriteLn ();
  Output_WriteString ((const char *) "@c under the terms of the GNU Free Documentation License, Version 1.2 or", 72);
  Output_WriteLn ();
  Output_WriteString ((const char *) "@c any later version published by the Free Software Foundation.", 63);
  Output_WriteLn ();
}


/*
   EmitRules - generates the BNF rules.
*/

static void EmitRules (void)
{
  if (Texinfo && FreeDocLicense)
    {
      EmitFDLNotice ();
    }
  ForeachRuleDo ((pge_DoProcedure) {(pge_DoProcedure_t) EmitRule});
}


/*
   DescribeElement -
*/

static void DescribeElement (unsigned int name)
{
  NameKey_Name lit;

  if (InitialElement)
    {
      InitialElement = FALSE;
    }
  else
    {
      Output_WriteString ((const char *) " |", 2);
    }
  Output_WriteLn ();
  Indent = 3;
  IndentString ((const char *) "", 0);
  Output_WriteKey (name);
  Output_WriteString ((const char *) ": ", 2);
  lit = static_cast<NameKey_Name> (SymbolKey_GetSymKey (ReverseAliases, name));
  if ((NameKey_MakeKey ((const char *) "\"", 1)) == lit)
    {
      Output_WriteString ((const char *) "str := ConCat(ConCatChar(ConCatChar(InitString(\"syntax error, found ", 68);
      Output_Write ('\'');
      Output_WriteString ((const char *) "\"), ", 4);
      Output_Write ('\'');
      Output_Write ('"');
      Output_Write ('\'');
      Output_WriteString ((const char *) "), ", 3);
      Output_Write ('"');
      Output_Write ('\'');
      Output_Write ('"');
      Output_WriteString ((const char *) "), Mark(str))", 13);
    }
  else if ((NameKey_MakeKey ((const char *) "'", 1)) == lit)
    {
      /* avoid dangling else.  */
      Output_WriteString ((const char *) "str := ConCat(ConCatChar(ConCatChar(InitString('syntax error, found ", 68);
      Output_Write ('"');
      Output_WriteString ((const char *) "'), ", 4);
      Output_Write ('"');
      Output_Write ('\'');
      Output_Write ('"');
      Output_WriteString ((const char *) "), ", 3);
      Output_Write ('\'');
      Output_Write ('"');
      Output_Write ('\'');
      Output_WriteString ((const char *) "), Mark(str))", 13);
    }
  else
    {
      /* avoid dangling else.  */
      Output_WriteString ((const char *) "str := ConCat(InitString(", 25);
      Output_Write ('"');
      Output_WriteString ((const char *) "syntax error, found ", 20);
      KeyWord (lit);
      Output_WriteString ((const char *) "\"), Mark(str))", 14);
    }
}


/*
   EmitInTestStop - construct a test for stop element, name.
*/

static void EmitInTestStop (NameKey_Name name)
{
  unsigned int i;
  unsigned int value;

  if (LargestValue <= MaxElementsInSet)
    {
      Output_WriteKey (name);
      Output_WriteString ((const char *) " IN stopset", 11);
      ParametersUsed |= (1 << (0 ));
    }
  else
    {
      value = static_cast<unsigned int> (SymbolKey_GetSymKey (Values, name));
      i = value / MaxElementsInSet;
      Output_WriteKey (name);
      Output_WriteString ((const char *) " IN stopset", 11);
      Output_WriteCard (i, 0);
      ParametersUsed |= (1 << (i ));
    }
}


/*
   DescribeStopElement -
*/

static void DescribeStopElement (unsigned int name)
{
  NameKey_Name lit;

  Indent = 3;
  IndentString ((const char *) "IF ", 3);
  EmitInTestStop (name);
  Output_WriteLn ();
  IndentString ((const char *) "THEN", 4);
  Output_WriteLn ();
  Indent = 6;
  lit = static_cast<NameKey_Name> (SymbolKey_GetSymKey (ReverseAliases, name));
  if ((lit == NameKey_NulName) || (lit == (NameKey_MakeKey ((const char *) "", 0))))
    {
      IndentString ((const char *) "(* ", 3);
      Output_WriteKey (name);
      Output_WriteString ((const char *) " has no token name (needed to generate error messages) *)", 57);
    }
  else if ((NameKey_MakeKey ((const char *) "'", 1)) == lit)
    {
      /* avoid dangling else.  */
      IndentString ((const char *) "message := ConCatChar(ConCatChar(ConCatChar(ConCatChar(ConCatChar(message, ", 75);
      Output_WriteString ((const char *) "' '), ", 6);
      Output_Write ('\'');
      Output_Write ('"');
      Output_WriteString ((const char *) "'), ", 4);
      Output_Write ('"');
      Output_Write ('\'');
      Output_WriteString ((const char *) "\"), ", 4);
      Output_Write ('\'');
      Output_Write ('"');
      Output_WriteString ((const char *) "'), ',') ; INC(n) ; ", 20);
    }
  else if ((NameKey_MakeKey ((const char *) "\"", 1)) == lit)
    {
      /* avoid dangling else.  */
      IndentString ((const char *) "message := ConCatChar(ConCatChar(ConCatChar(ConCatChar(ConCatChar(message, ", 75);
      Output_WriteString ((const char *) "\" \"), ", 6);
      Output_Write ('"');
      Output_Write ('`');
      Output_WriteString ((const char *) "\"), ", 4);
      Output_Write ('\'');
      Output_Write ('"');
      Output_WriteString ((const char *) "'), ", 4);
      Output_Write ('"');
      Output_Write ('\'');
      Output_WriteString ((const char *) "\"), \",\") ; INC(n) ; ", 20);
    }
  else
    {
      /* avoid dangling else.  */
      IndentString ((const char *) "message := ConCat(ConCatChar(message, ' ", 40);
      Output_WriteString ((const char *) "'), ", 4);
      Output_WriteString ((const char *) "Mark(InitString(\"", 17);
      KeyWord (lit);
      Output_Write ('"');
      Output_WriteString ((const char *) "))) ; INC(n)", 12);
    }
  Output_WriteLn ();
  Indent = 3;
  IndentString ((const char *) "END ;", 5);
  Output_WriteLn ();
}


/*
   EmitDescribeStop -
*/

static void EmitDescribeStop (void)
{
  DynamicStrings_String s;

  Output_WriteLn ();
  Indent = 0;
  IndentString ((const char *) "(*", 2);
  Indent = 3;
  Output_WriteLn ();
  IndentString ((const char *) "DescribeStop - issues a message explaining what tokens were expected", 68);
  Output_WriteLn ();
  Output_WriteString ((const char *) "*)", 2);
  Output_WriteLn ();
  Output_WriteLn ();
  Indent = 0;
  IndentString ((const char *) "PROCEDURE DescribeStop (", 24);
  ParametersUsed = (unsigned int) 0;
  Output_StartBuffer ();
  Output_WriteString ((const char *) ") : String ;", 12);
  Output_WriteLn ();
  IndentString ((const char *) "VAR", 3);
  Output_WriteLn ();
  Indent = 3;
  IndentString ((const char *) "n      : CARDINAL ;", 19);
  Output_WriteLn ();
  IndentString ((const char *) "str,", 4);
  Output_WriteLn ();
  IndentString ((const char *) "message: String ;", 17);
  Output_WriteLn ();
  Indent = 0;
  IndentString ((const char *) "BEGIN", 5);
  Output_WriteLn ();
  Indent = 3;
  IndentString ((const char *) "n := 0 ;", 8);
  Output_WriteLn ();
  IndentString ((const char *) "message := InitString('') ;", 27);
  Output_WriteLn ();
  SymbolKey_ForeachNodeDo (Aliases, (SymbolKey_PerformOperation) {(SymbolKey_PerformOperation_t) DescribeStopElement});
  Output_WriteLn ();
  Indent = 3;
  IndentString ((const char *) "IF n=0", 6);
  Output_WriteLn ();
  IndentString ((const char *) "THEN", 4);
  Output_WriteLn ();
  Indent = 6;
  IndentString ((const char *) "str := InitString(' syntax error') ; ", 37);
  Output_WriteLn ();
  IndentString ((const char *) "message := KillString(message) ; ", 33);
  Output_WriteLn ();
  Indent = 3;
  IndentString ((const char *) "ELSIF n=1", 9);
  Output_WriteLn ();
  IndentString ((const char *) "THEN", 4);
  Output_WriteLn ();
  Indent = 6;
  IndentString ((const char *) "str := ConCat(message, Mark(InitString(' missing '))) ;", 55);
  Output_WriteLn ();
  Indent = 3;
  IndentString ((const char *) "ELSE", 4);
  Output_WriteLn ();
  Indent = 6;
  IndentString ((const char *) "str := ConCat(InitString(' expecting one of'), message) ;", 57);
  Output_WriteLn ();
  IndentString ((const char *) "message := KillString(message) ;", 32);
  Output_WriteLn ();
  Indent = 3;
  IndentString ((const char *) "END ;", 5);
  Output_WriteLn ();
  IndentString ((const char *) "RETURN( str )", 13);
  Output_WriteLn ();
  Indent = 0;
  IndentString ((const char *) "END DescribeStop ;", 18);
  Output_WriteLn ();
  Output_WriteLn ();
  s = Output_EndBuffer ();
  EmitStopParameters (TRUE);
  Output_KillWriteS (s);
}


/*
   EmitDescribeError -
*/

static void EmitDescribeError (void)
{
  Output_WriteLn ();
  Indent = 0;
  IndentString ((const char *) "(*", 2);
  Output_WriteLn ();
  Indent = 3;
  IndentString ((const char *) "DescribeError - issues a message explaining what tokens were expected", 69);
  Output_WriteLn ();
  Indent = 0;
  IndentString ((const char *) "*)", 2);
  Output_WriteLn ();
  Output_WriteLn ();
  IndentString ((const char *) "PROCEDURE DescribeError ;", 25);
  Output_WriteLn ();
  IndentString ((const char *) "VAR", 3);
  Output_WriteLn ();
  Indent = 3;
  IndentString ((const char *) "str: String ;", 13);
  Output_WriteLn ();
  Indent = 0;
  IndentString ((const char *) "BEGIN", 5);
  Output_WriteLn ();
  Indent = 3;
  IndentString ((const char *) "str := InitString('') ;", 23);
  Output_WriteLn ();
  /* was
   IndentString('str := DescribeStop(') ; EmitStopParameters(FALSE) ; Output.WriteString(') ;') ; Output.WriteLn ;
  */
  IndentString ((const char *) "CASE ", 5);
  WriteGetTokenType ();
  Output_WriteString ((const char *) " OF", 3);
  NewLine (3);
  InitialElement = TRUE;
  SymbolKey_ForeachNodeDo (Aliases, (SymbolKey_PerformOperation) {(SymbolKey_PerformOperation_t) DescribeElement});
  Output_WriteLn ();
  Indent = 3;
  IndentString ((const char *) "ELSE", 4);
  Output_WriteLn ();
  IndentString ((const char *) "END ;", 5);
  Output_WriteLn ();
  IndentString ((const char *) "", 0);
  Output_WriteKey (ErrorProcString);
  Output_WriteString ((const char *) "(str) ;", 7);
  Output_WriteLn ();
  Indent = 0;
  IndentString ((const char *) "END DescribeError ;", 19);
  Output_WriteLn ();
}


/*
   EmitSetTypes - write out the set types used during error recovery
*/

static void EmitSetTypes (void)
{
  unsigned int i;
  unsigned int j;
  unsigned int m;
  unsigned int n;

  Output_WriteString ((const char *) "(*", 2);
  NewLine (3);
  Output_WriteString ((const char *) "expecting token set defined as an enumerated type", 49);
  NewLine (3);
  Output_WriteString ((const char *) "(", 1);
  i = 0;
  while (i < LargestValue)
    {
      Output_WriteKey (SymbolKey_GetSymKey (ReverseValues, (unsigned int ) (i)));
      i += 1;
      if (i < LargestValue)
        {
          Output_WriteString ((const char *) ", ", 2);
        }
    }
  Output_WriteString ((const char *) ") ;", 3);
  NewLine (0);
  Output_WriteString ((const char *) "*)", 2);
  NewLine (0);
  Output_WriteString ((const char *) "TYPE", 4);
  NewLine (3);
  if (LargestValue > MaxElementsInSet)
    {
      i = 0;
      n = LargestValue / MaxElementsInSet;
      while (i <= n)
        {
          j = i*MaxElementsInSet;
          if (LargestValue < (((i+1)*MaxElementsInSet)-1))
            {
              m = LargestValue-1;
            }
          else
            {
              m = ((i+1)*MaxElementsInSet)-1;
            }
          Output_WriteString ((const char *) "stop", 4);
          Output_WriteCard (i, 0);
          Output_WriteString ((const char *) " = [", 4);
          Output_WriteKey (SymbolKey_GetSymKey (ReverseValues, (unsigned int ) (j)));
          Output_WriteString ((const char *) "..", 2);
          Output_WriteKey (SymbolKey_GetSymKey (ReverseValues, (unsigned int ) (m)));
          Output_WriteString ((const char *) "] ;", 3);
          NewLine (3);
          Output_WriteString ((const char *) "SetOfStop", 9);
          Output_WriteCard (i, 0);
          Output_WriteString ((const char *) " = SET OF stop", 14);
          Output_WriteCard (i, 0);
          Output_WriteString ((const char *) " ;", 2);
          NewLine (3);
          i += 1;
        }
    }
  else
    {
      Output_WriteString ((const char *) "SetOfStop", 9);
      Output_WriteString ((const char *) " = SET OF [", 11);
      Output_WriteKey (SymbolKey_GetSymKey (ReverseValues, (unsigned int ) (0)));
      Output_WriteString ((const char *) "..", 2);
      Output_WriteKey (SymbolKey_GetSymKey (ReverseValues, (unsigned int ) (LargestValue-1)));
      Output_WriteString ((const char *) "] ;", 3);
    }
  NewLine (0);
}


/*
   EmitSupport - generates the support routines.
*/

static void EmitSupport (void)
{
  if (ErrorRecovery)
    {
      EmitSetTypes ();
      EmitDescribeStop ();
      EmitDescribeError ();
    }
}


/*
   DisposeSetDesc - dispose of the set list, s.
*/

static void DisposeSetDesc (pge_SetDesc *s)
{
  pge_SetDesc h;
  pge_SetDesc n;

  if ((*s) != NULL)
    {
      h = (*s);
      n = (*s)->next;
      do {
        Storage_DEALLOCATE ((void **) &h, sizeof (pge__T7));
        h = n;
        if (n != NULL)
          {
            n = n->next;
          }
      } while (! (h == NULL));
      (*s) = NULL;
    }
}


/*
   OptionalFactor -
*/

static unsigned int OptionalFactor (pge_FactorDesc f)
{
  while (f != NULL)
    {
      switch (f->type)
        {
          case pge_id:
            break;

          case pge_lit:
            break;

          case pge_sub:
          case pge_opt:
          case pge_mult:
            if (OptionalExpression (f->expr))
              {
                return TRUE;
              }
            break;

          case pge_m2:
            break;


          default:
            break;
        }
      f = f->next;
    }
  return FALSE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   OptionalTerm - returns TRUE if the term maybe empty.
*/

static unsigned int OptionalTerm (pge_TermDesc t)
{
  pge_TermDesc u;
  pge_TermDesc v;
  pge_SetDesc tov;
  pge_SetDesc tou;

  u = t;
  while (u != NULL)
    {
      if (OptionalFactor (u->factor))
        {
          return TRUE;
        }
      v = t;
      tou = NULL;
      CalcFirstFactor (u->factor, NULL, &tou);
      while (v != NULL)
        {
          if (v != u)
            {
              tov = NULL;
              CalcFirstFactor (v->factor, NULL, &tov);
              if (IntersectionIsNil (tov, tou))
                {
                  DisposeSetDesc (&tov);
                }
              else
                {
                  StrIO_WriteString ((const char *) "problem with two first sets. Set 1: ", 36);
                  EmitSet (tou, static_cast<unsigned int> (0), static_cast<unsigned int> (0));
                  StrIO_WriteLn ();
                  StrIO_WriteString ((const char *) "                             Set 2: ", 36);
                  EmitSet (tov, static_cast<unsigned int> (0), static_cast<unsigned int> (0));
                  StrIO_WriteLn ();
                  DisposeSetDesc (&tou);
                  DisposeSetDesc (&tov);
                  return TRUE;
                }
            }
          v = v->next;
        }
      DisposeSetDesc (&tou);
      u = u->next;
    }
  return FALSE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   OptionalExpression -
*/

static unsigned int OptionalExpression (pge_ExpressionDesc e)
{
  if (e == NULL)
    {
      return FALSE;
    }
  else
    {
      return OptionalTerm (e->term);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   OptionalStatement - returns FALSE if statement, s, does not have a optional ambiguity.
*/

static unsigned int OptionalStatement (pge_StatementDesc s)
{
  if (s == NULL)
    {
      return FALSE;
    }
  else
    {
      return OptionalExpression (s->expr);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   OptionalProduction -
*/

static unsigned int OptionalProduction (pge_ProductionDesc p)
{
  if (p == NULL)
    {
      return FALSE;
    }
  else
    {
      return OptionalStatement (p->statement);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   CheckFirstFollow -
*/

static unsigned int CheckFirstFollow (pge_FactorDesc f, pge_FactorDesc after)
{
  pge_SetDesc first;
  pge_SetDesc follow;

  first = NULL;
  CalcFirstFactor (f, NULL, &first);
  follow = NULL;
  follow = GetFollow (f->followinfo);
  if (IntersectionIsNil (first, follow))
    {
      DisposeSetDesc (&first);
      DisposeSetDesc (&follow);
      return FALSE;
    }
  else
    {
      PrettyCommentFactor (f, 3);
      NewLine (3);
      StrIO_WriteString ((const char *) "first: ", 7);
      EmitSet (first, static_cast<unsigned int> (0), static_cast<unsigned int> (0));
      NewLine (3);
      StrIO_WriteString ((const char *) "follow: ", 8);
      EmitSet (follow, static_cast<unsigned int> (0), static_cast<unsigned int> (0));
      NewLine (3);
      DisposeSetDesc (&first);
      DisposeSetDesc (&follow);
      return TRUE;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   ConstrainedEmptyFactor -
*/

static unsigned int ConstrainedEmptyFactor (pge_FactorDesc f)
{
  while (f != NULL)
    {
      switch (f->type)
        {
          case pge_id:
            break;

          case pge_lit:
            break;

          case pge_sub:
          case pge_opt:
          case pge_mult:
            if (ConstrainedEmptyExpression (f->expr))
              {
                return TRUE;
              }
            break;

          case pge_m2:
            break;


          default:
            break;
        }
      if (((f->type != pge_m2) && (EmptyFactor (f))) && (CheckFirstFollow (f, f->next)))
        {
          return TRUE;
        }
      f = f->next;
    }
  return FALSE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   ConstrainedEmptyTerm - returns TRUE if the term maybe empty.
*/

static unsigned int ConstrainedEmptyTerm (pge_TermDesc t)
{
  pge_SetDesc first;
  pge_SetDesc follow;

  while (t != NULL)
    {
      if (ConstrainedEmptyFactor (t->factor))
        {
          return TRUE;
        }
      else if (((t->factor->type != pge_m2) && (EmptyFactor (t->factor))) && (CheckFirstFollow (t->factor, t->factor->next)))
        {
          /* avoid dangling else.  */
          return TRUE;
        }
      t = t->next;
    }
  return FALSE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   ConstrainedEmptyExpression -
*/

static unsigned int ConstrainedEmptyExpression (pge_ExpressionDesc e)
{
  if (e == NULL)
    {
      return FALSE;
    }
  else
    {
      return ConstrainedEmptyTerm (e->term);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   ConstrainedEmptyStatement - returns FALSE if statement, s, does not have a optional ambiguity.
*/

static unsigned int ConstrainedEmptyStatement (pge_StatementDesc s)
{
  if (s == NULL)
    {
      return FALSE;
    }
  else
    {
      return ConstrainedEmptyExpression (s->expr);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   ConstrainedEmptyProduction - returns TRUE if a problem exists with, p.
*/

static unsigned int ConstrainedEmptyProduction (pge_ProductionDesc p)
{
  if (p == NULL)
    {
      return FALSE;
    }
  else
    {
      return ConstrainedEmptyStatement (p->statement);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   TestForLALR1 -
*/

static void TestForLALR1 (pge_ProductionDesc p)
{
  if (OptionalProduction (p))
    {
      WarnError1 ((const char *) "production %s has two optional sentances using | which both have the same start symbols", 87, p->statement->ident->name);
      WasNoError = FALSE;
      PrettyCommentProduction (p);
    }
}


/*
   DoEpsilon - runs the epsilon interrelated rules
*/

static void DoEpsilon (pge_ProductionDesc p)
{
  CalcEpsilonProduction (p);
  CalcReachEndProduction (p);
}


/*
   CheckComplete - checks that production, p, is complete.
*/

static void CheckComplete (pge_ProductionDesc p)
{
  if ((GetReachEnd (p->followinfo)) == pge_unknown)
    {
      PrettyCommentProduction (p);
      WarnError1 ((const char *) "cannot determine epsilon, probably a left recursive rule in %s and associated rules (hint rewrite using ebnf and eliminate left recursion)", 138, p->statement->ident->name);
      WasNoError = FALSE;
    }
}


/*
   PostProcessRules - backpatch the ident to rule definitions and emit comments and code.
*/

static void PostProcessRules (void)
{
  ForeachRuleDo ((pge_DoProcedure) {(pge_DoProcedure_t) BackPatchIdentToDefinitions});
  if (! WasNoError)
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
  WhileNotCompleteDo ((pge_DoProcedure) {(pge_DoProcedure_t) DoEpsilon});
  if (! WasNoError)
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
  ForeachRuleDo ((pge_DoProcedure) {(pge_DoProcedure_t) CheckComplete});
  if (! WasNoError)
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
  WhileNotCompleteDo ((pge_DoProcedure) {(pge_DoProcedure_t) CalculateFirstAndFollow});
  if (! WasNoError)
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
  ForeachRuleDo ((pge_DoProcedure) {(pge_DoProcedure_t) TestForLALR1});
  if (! WasNoError)
    {
      ForeachRuleDo ((pge_DoProcedure) {(pge_DoProcedure_t) PrettyCommentProduction});
    }
}


/*
   DisplayHelp - display a summary help and then exit (0).
*/

static void DisplayHelp (void)
{
  StrIO_WriteString ((const char *) "Usage: pge [-l] [-c] [-d] [-e] [-k] [-t] [-k] [-p] [-x] [-f] [-o outputfile] filename", 85);
  StrIO_WriteLn ();
  StrIO_WriteString ((const char *) "   -l             suppress file and line source information", 59);
  StrIO_WriteLn ();
  StrIO_WriteString ((const char *) "   -c             do not generate any Modula-2 code within the parser rules", 75);
  StrIO_WriteLn ();
  StrIO_WriteString ((const char *) "   -h or --help   generate this help message", 44);
  StrIO_WriteLn ();
  StrIO_WriteString ((const char *) "   -e             do not generate a parser with error recovery", 62);
  StrIO_WriteLn ();
  StrIO_WriteString ((const char *) "   -k             generate keyword errors with GCC formatting directives", 72);
  StrIO_WriteLn ();
  StrIO_WriteString ((const char *) "   -d             generate internal debugging information", 57);
  StrIO_WriteLn ();
  StrIO_WriteString ((const char *) "   -p             only display the ebnf rules", 45);
  StrIO_WriteLn ();
  StrIO_WriteString ((const char *) "   -t             generate texinfo formating for pretty printing (-p)", 69);
  StrIO_WriteLn ();
  StrIO_WriteString ((const char *) "   -x             generate sphinx formating for pretty printing (-p)", 68);
  StrIO_WriteLn ();
  StrIO_WriteString ((const char *) "   -f             generate GNU Free Documentation header before pretty printing in texinfo", 90);
  StrIO_WriteLn ();
  StrIO_WriteString ((const char *) "   -o             write output to filename", 42);
  StrIO_WriteLn ();
  libc_exit (0);
}


/*
   ParseArgs -
*/

static void ParseArgs (void)
{
  unsigned int n;
  unsigned int i;

  ErrorRecovery = TRUE;  /* DefaultRecovery ;  */
  Debugging = FALSE;  /* DefaultRecovery ;  */
  PrettyPrint = FALSE;
  KeywordFormatting = FALSE;
  i = 1;
  n = Args_Narg ();
  while (i < n)
    {
      if (Args_GetArg ((char *) &ArgName.array[0], MaxFileName, i))
        {
          /* avoid gcc warning by using compound statement even if not strictly necessary.  */
          if (StrLib_StrEqual ((const char *) &ArgName.array[0], MaxFileName, (const char *) "-e", 2))
            {
              ErrorRecovery = FALSE;
            }
          else if (StrLib_StrEqual ((const char *) &ArgName.array[0], MaxFileName, (const char *) "-d", 2))
            {
              /* avoid dangling else.  */
              Debugging = TRUE;
              bnflex_SetDebugging (TRUE);
            }
          else if (StrLib_StrEqual ((const char *) &ArgName.array[0], MaxFileName, (const char *) "-c", 2))
            {
              /* avoid dangling else.  */
              EmitCode = FALSE;
            }
          else if (StrLib_StrEqual ((const char *) &ArgName.array[0], MaxFileName, (const char *) "-k", 2))
            {
              /* avoid dangling else.  */
              KeywordFormatting = TRUE;
            }
          else if (StrLib_StrEqual ((const char *) &ArgName.array[0], MaxFileName, (const char *) "-l", 2))
            {
              /* avoid dangling else.  */
              SuppressFileLineTag = TRUE;
            }
          else if ((StrLib_StrEqual ((const char *) &ArgName.array[0], MaxFileName, (const char *) "-h", 2)) || (StrLib_StrEqual ((const char *) &ArgName.array[0], MaxFileName, (const char *) "--help", 6)))
            {
              /* avoid dangling else.  */
              DisplayHelp ();
            }
          else if (StrLib_StrEqual ((const char *) &ArgName.array[0], MaxFileName, (const char *) "-p", 2))
            {
              /* avoid dangling else.  */
              PrettyPrint = TRUE;
            }
          else if (StrLib_StrEqual ((const char *) &ArgName.array[0], MaxFileName, (const char *) "-t", 2))
            {
              /* avoid dangling else.  */
              Texinfo = TRUE;
            }
          else if (StrLib_StrEqual ((const char *) &ArgName.array[0], MaxFileName, (const char *) "-x", 2))
            {
              /* avoid dangling else.  */
              Sphinx = TRUE;
            }
          else if (StrLib_StrEqual ((const char *) &ArgName.array[0], MaxFileName, (const char *) "-f", 2))
            {
              /* avoid dangling else.  */
              FreeDocLicense = TRUE;
            }
          else if (StrLib_StrEqual ((const char *) &ArgName.array[0], MaxFileName, (const char *) "-o", 2))
            {
              /* avoid dangling else.  */
              i += 1;
              if (Args_GetArg ((char *) &ArgName.array[0], MaxFileName, i))
                {
                  if (! (Output_Open ((const char *) &ArgName.array[0], MaxFileName)))
                    {
                      StrIO_WriteString ((const char *) "cannot open ", 12);
                      StrIO_WriteString ((const char *) &ArgName.array[0], MaxFileName);
                      StrIO_WriteString ((const char *) " for writing", 12);
                      StrIO_WriteLn ();
                      libc_exit (1);
                    }
                }
            }
          else if (bnflex_OpenSource ((const char *) &ArgName.array[0], MaxFileName))
            {
              /* avoid dangling else.  */
              StrLib_StrCopy ((const char *) &ArgName.array[0], MaxFileName, (char *) &FileName.array[0], MaxFileName);
              bnflex_AdvanceToken ();
            }
          else
            {
              /* avoid dangling else.  */
              StrIO_WriteString ((const char *) "cannot open ", 12);
              StrIO_WriteString ((const char *) &ArgName.array[0], MaxFileName);
              StrIO_WriteString ((const char *) " for reading", 12);
              StrIO_WriteLn ();
              libc_exit (1);
            }
        }
      i += 1;
    }
  if (n == 1)
    {
      DisplayHelp ();
    }
}


/*
   Init - initialize the modules data structures
*/

static void Init (void)
{
  WasNoError = TRUE;
  Texinfo = FALSE;
  Sphinx = FALSE;
  FreeDocLicense = FALSE;
  EmitCode = TRUE;
  LargestValue = 0;
  HeadProduction = NULL;
  CurrentProduction = NULL;
  SymbolKey_InitTree (&Aliases);
  SymbolKey_InitTree (&ReverseAliases);
  SymbolKey_InitTree (&Values);
  SymbolKey_InitTree (&ReverseValues);
  LastLineNo = 0;
  CodePrologue = NULL;
  CodeEpilogue = NULL;
  CodeDeclaration = NULL;
  ErrorProcArray = NameKey_MakeKey ((const char *) "Error", 5);
  ErrorProcString = NameKey_MakeKey ((const char *) "ErrorS", 6);
  TokenTypeProc = NameKey_MakeKey ((const char *) "GetCurrentTokenType()", 21);
  SymIsProc = NameKey_MakeKey ((const char *) "SymIs", 5);
  OnLineStart = TRUE;
  ParseArgs ();
  Main (static_cast<pge_SetOfStop> ((unsigned int) ((1 << (bnflex_eoftok)))));  /* this line will be manipulated by sed in buildpg  */
  if (WasNoError)  /* this line will be manipulated by sed in buildpg  */
    {
      PostProcessRules ();
      if (WasNoError)
        {
          /* avoid gcc warning by using compound statement even if not strictly necessary.  */
          if (Debugging)
            {
              EmitRules ();
            }
          else if (PrettyPrint)
            {
              /* avoid dangling else.  */
              EmitRules ();
            }
          else
            {
              /* avoid dangling else.  */
              Output_WriteString ((const char *) "(* it is advisable not to edit this file as it was automatically generated from the grammer file ", 97);
              Output_WriteString ((const char *) &FileName.array[0], MaxFileName);
              Output_WriteString ((const char *) " *)", 3);
              Output_WriteLn ();
              OnLineStart = FALSE;
              EmitFileLineTag (LinePrologue);
              BeginningOfLine = TRUE;
              WriteCodeHunkList (CodePrologue);
              EmitSupport ();
              EmitFileLineTag (LineDeclaration);
              WriteCodeHunkList (CodeDeclaration);
              EmitRules ();
              /* code rules  */
              EmitFileLineTag (LineEpilogue);
              WriteCodeHunkList (CodeEpilogue);
            }
        }
    }
  Output_Close ();
}

extern "C" void _M2_pge_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
  Init ();
}

extern "C" void _M2_pge_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}
